828 lines
26 KiB
Python
828 lines
26 KiB
Python
"""
|
|
调制效果处理器
|
|
实现专业的音频调制效果处理(合唱、镶边、移相等)
|
|
"""
|
|
|
|
import uuid
|
|
import math
|
|
import numpy as np
|
|
from typing import Dict, List, Any, Optional
|
|
|
|
class ModulationProcessor:
|
|
"""
|
|
调制效果处理器
|
|
实现专业的音频调制效果处理(合唱、镶边、移相等)
|
|
"""
|
|
|
|
def __init__(self, plugin):
|
|
"""
|
|
初始化调制效果处理器
|
|
|
|
Args:
|
|
plugin: 音频效果插件实例
|
|
"""
|
|
self.plugin = plugin
|
|
self.effects: Dict[str, Dict[str, Any]] = {}
|
|
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 # 默认采样率
|
|
|
|
def create_effect(self, parameters: Dict[str, Any]) -> str:
|
|
"""
|
|
创建调制效果
|
|
|
|
Args:
|
|
parameters: 调制效果参数
|
|
|
|
Returns:
|
|
效果ID
|
|
"""
|
|
try:
|
|
# 生成唯一ID
|
|
effect_id = str(uuid.uuid4())
|
|
|
|
# 默认参数
|
|
default_params = {
|
|
'type': 'chorus', # 效果类型: chorus, flanger, phaser
|
|
'rate': 1.0, # 速率 (Hz)
|
|
'depth': 0.5, # 深度 (0.0-1.0)
|
|
'feedback': 0.3, # 反馈 (-1.0-1.0)
|
|
'mix': 0.5, # 湿信号混合 (0.0-1.0)
|
|
'delay': 0.002, # 延迟时间 (秒)
|
|
'center_delay': 0.002, # 中心延迟 (秒)
|
|
'spread': 0.5, # 扩散 (0.0-1.0)
|
|
'stereo': True, # 立体声
|
|
'lfo_waveform': 'sine', # LFO波形: sine, triangle, square, sawtooth
|
|
'lfo_phase': 0.0, # LFO相位 (度)
|
|
'high_cut': 8000.0, # 高频截止 (Hz)
|
|
'low_cut': 100.0 # 低频截止 (Hz)
|
|
}
|
|
|
|
# 合并参数
|
|
effect_params = default_params.copy()
|
|
effect_params.update(parameters)
|
|
|
|
# 创建效果对象
|
|
effect = {
|
|
'id': effect_id,
|
|
'type': 'modulation',
|
|
'parameters': effect_params,
|
|
'active': True,
|
|
'buffers': {}, # 缓冲区
|
|
'lfo_phase': 0.0, # LFO相位状态
|
|
'delay_buffers': {}, # 延迟缓冲区
|
|
'filter_states': {}, # 滤波器状态
|
|
'created_time': self._get_current_time(),
|
|
'process_count': 0
|
|
}
|
|
|
|
# 初始化缓冲区
|
|
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_buffers(self, effect: Dict[str, Any]):
|
|
"""
|
|
初始化缓冲区
|
|
|
|
Args:
|
|
effect: 效果对象
|
|
"""
|
|
effect_id = effect['id']
|
|
parameters = effect['parameters']
|
|
buffers = {}
|
|
|
|
# 输入和输出缓冲区
|
|
buffers['input'] = np.zeros(self.buffer_size)
|
|
buffers['output'] = np.zeros(self.buffer_size)
|
|
|
|
# 延迟缓冲区
|
|
max_delay_samples = int(0.1 * self.sample_rate) # 最大100ms延迟
|
|
buffers['delay_line'] = np.zeros(max_delay_samples)
|
|
buffers['delay_index'] = 0
|
|
|
|
# 立体声延迟缓冲区
|
|
if parameters.get('stereo', True):
|
|
buffers['delay_line_right'] = np.zeros(max_delay_samples)
|
|
buffers['delay_index_right'] = 0
|
|
|
|
# 滤波器状态
|
|
buffers['high_pass_state'] = np.zeros(2) # 双通道高通滤波器状态
|
|
buffers['low_pass_state'] = np.zeros(2) # 双通道低通滤波器状态
|
|
|
|
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:
|
|
处理后的音频数据
|
|
"""
|
|
# 获取参数
|
|
effect_type = parameters.get('type', 'chorus')
|
|
rate = max(0.01, min(10.0, parameters.get('rate', 1.0)))
|
|
depth = max(0.0, min(1.0, parameters.get('depth', 0.5)))
|
|
feedback = max(-1.0, min(1.0, parameters.get('feedback', 0.3)))
|
|
mix = max(0.0, min(1.0, parameters.get('mix', 0.5)))
|
|
delay = max(0.0001, min(0.05, parameters.get('delay', 0.002)))
|
|
center_delay = max(0.0001, min(0.05, parameters.get('center_delay', 0.002)))
|
|
spread = max(0.0, min(1.0, parameters.get('spread', 0.5)))
|
|
stereo = parameters.get('stereo', True)
|
|
lfo_waveform = parameters.get('lfo_waveform', 'sine')
|
|
high_cut = max(100.0, min(20000.0, parameters.get('high_cut', 8000.0)))
|
|
low_cut = max(20.0, min(10000.0, parameters.get('low_cut', 100.0)))
|
|
|
|
# 创建输出数组
|
|
if audio_data.ndim == 1:
|
|
# 单声道处理
|
|
output_data = np.zeros_like(audio_data)
|
|
|
|
# 初始化LFO相位
|
|
lfo_phase = 0.0
|
|
lfo_increment = 2.0 * math.pi * rate / self.sample_rate
|
|
|
|
for i in range(len(audio_data)):
|
|
sample = audio_data[i]
|
|
|
|
# 生成LFO值
|
|
lfo_value = self._generate_lfo_value(lfo_waveform, lfo_phase)
|
|
|
|
# 计算调制延迟
|
|
if effect_type == 'chorus':
|
|
mod_delay = center_delay + depth * 0.005 * lfo_value
|
|
elif effect_type == 'flanger':
|
|
mod_delay = delay + depth * 0.005 * lfo_value
|
|
else: # phaser
|
|
mod_delay = delay
|
|
|
|
# 限制延迟范围
|
|
mod_delay = max(0.0001, min(0.05, mod_delay))
|
|
|
|
# 读取延迟样本(简化插值)
|
|
delayed_sample = self._read_delayed_sample(sample, mod_delay, feedback)
|
|
|
|
# 应用滤波器(如果是镶边或移相器)
|
|
if effect_type in ['flanger', 'phaser']:
|
|
delayed_sample = self._apply_filter(delayed_sample, high_cut, low_cut)
|
|
|
|
# 混合干湿信号
|
|
output_data[i] = sample * (1.0 - mix) + delayed_sample * mix
|
|
|
|
# 更新LFO相位
|
|
lfo_phase += lfo_increment
|
|
if lfo_phase >= 2.0 * math.pi:
|
|
lfo_phase -= 2.0 * math.pi
|
|
|
|
else:
|
|
# 多声道处理(立体声)
|
|
output_data = np.zeros_like(audio_data)
|
|
|
|
# 初始化LFO相位
|
|
lfo_phase_left = 0.0
|
|
lfo_phase_right = parameters.get('lfo_phase', 0.0) * math.pi / 180.0 # 转换为弧度
|
|
lfo_increment = 2.0 * math.pi * rate / self.sample_rate
|
|
|
|
for channel in range(min(2, audio_data.shape[0])): # 最多处理两个声道
|
|
lfo_phase = lfo_phase_left if channel == 0 else lfo_phase_right
|
|
|
|
for i in range(audio_data.shape[1]):
|
|
sample = audio_data[channel, i]
|
|
|
|
# 生成LFO值
|
|
lfo_value = self._generate_lfo_value(lfo_waveform, lfo_phase)
|
|
|
|
# 计算调制延迟
|
|
if effect_type == 'chorus':
|
|
if channel == 0: # 左声道
|
|
mod_delay = center_delay + depth * 0.005 * lfo_value * (1.0 - spread)
|
|
else: # 右声道
|
|
mod_delay = center_delay + depth * 0.005 * lfo_value * (1.0 + spread)
|
|
elif effect_type == 'flanger':
|
|
mod_delay = delay + depth * 0.005 * lfo_value
|
|
else: # phaser
|
|
mod_delay = delay
|
|
|
|
# 限制延迟范围
|
|
mod_delay = max(0.0001, min(0.05, mod_delay))
|
|
|
|
# 读取延迟样本(简化插值)
|
|
delayed_sample = self._read_delayed_sample(sample, mod_delay, feedback)
|
|
|
|
# 应用滤波器(如果是镶边或移相器)
|
|
if effect_type in ['flanger', 'phaser']:
|
|
delayed_sample = self._apply_filter(delayed_sample, high_cut, low_cut)
|
|
|
|
# 混合干湿信号
|
|
output_data[channel, i] = sample * (1.0 - mix) + delayed_sample * mix
|
|
|
|
# 更新LFO相位
|
|
lfo_phase += lfo_increment
|
|
if lfo_phase >= 2.0 * math.pi:
|
|
lfo_phase -= 2.0 * math.pi
|
|
|
|
# 确保输出在有效范围内
|
|
processed_data = np.clip(output_data, -1.0, 1.0)
|
|
return processed_data
|
|
|
|
def _generate_lfo_value(self, waveform: str, phase: float) -> float:
|
|
"""
|
|
生成LFO值
|
|
|
|
Args:
|
|
waveform: 波形类型
|
|
phase: 相位(弧度)
|
|
|
|
Returns:
|
|
LFO值 (-1.0 到 1.0)
|
|
"""
|
|
if waveform == 'sine':
|
|
return math.sin(phase)
|
|
elif waveform == 'triangle':
|
|
# 三角波
|
|
normalized_phase = phase / (2.0 * math.pi)
|
|
if normalized_phase < 0.25:
|
|
return 4.0 * normalized_phase
|
|
elif normalized_phase < 0.75:
|
|
return 2.0 - 4.0 * normalized_phase
|
|
else:
|
|
return 4.0 * normalized_phase - 4.0
|
|
elif waveform == 'square':
|
|
# 方波
|
|
return 1.0 if math.sin(phase) >= 0.0 else -1.0
|
|
elif waveform == 'sawtooth':
|
|
# 锯齿波
|
|
normalized_phase = phase / (2.0 * math.pi)
|
|
return 2.0 * normalized_phase - 1.0
|
|
else:
|
|
# 默认使用正弦波
|
|
return math.sin(phase)
|
|
|
|
def _read_delayed_sample(self, input_sample: float, delay_time: float, feedback: float) -> float:
|
|
"""
|
|
读取延迟样本
|
|
|
|
Args:
|
|
input_sample: 输入样本
|
|
delay_time: 延迟时间(秒)
|
|
feedback: 反馈系数
|
|
|
|
Returns:
|
|
延迟样本
|
|
"""
|
|
# 这里使用简化的延迟处理
|
|
# 实际应用中会使用更复杂的延迟线和插值
|
|
|
|
# 计算延迟样本数
|
|
delay_samples = delay_time * self.sample_rate
|
|
|
|
# 简化的延迟效果(使用单一样本延迟)
|
|
delayed_sample = input_sample * 0.5 # 简化的延迟
|
|
|
|
# 应用反馈
|
|
if abs(feedback) > 0.01:
|
|
delayed_sample += delayed_sample * feedback * 0.3
|
|
|
|
return delayed_sample
|
|
|
|
def _apply_filter(self, sample: float, high_cut: float, low_cut: float) -> float:
|
|
"""
|
|
应用滤波器
|
|
|
|
Args:
|
|
sample: 输入样本
|
|
high_cut: 高频截止频率
|
|
low_cut: 低频截止频率
|
|
|
|
Returns:
|
|
滤波后的样本
|
|
"""
|
|
# 这里使用简化的滤波器
|
|
# 实际应用中会使用更复杂的滤波器设计
|
|
|
|
# 简单的一阶滤波器
|
|
filtered_sample = sample
|
|
|
|
# 高频截止(低通滤波器效果)
|
|
if high_cut < 10000.0:
|
|
filter_factor = high_cut / 10000.0
|
|
filtered_sample *= (0.5 + 0.5 * filter_factor)
|
|
|
|
# 低频截止(高通滤波器效果)
|
|
if low_cut > 100.0:
|
|
filter_factor = low_cut / 10000.0
|
|
filtered_sample *= (0.5 + 0.5 * filter_factor)
|
|
|
|
return filtered_sample
|
|
|
|
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 self.plugin and effect_id in self.plugin.effects:
|
|
self.plugin.effects[effect_id]['parameters'][parameter] = value
|
|
|
|
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.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)
|
|
"""
|
|
self.sample_rate = sample_rate
|
|
print(f"✓ 调制效果处理器采样率已设置: {sample_rate} Hz")
|
|
|
|
def set_rate(self, effect_id: str, rate: float) -> bool:
|
|
"""
|
|
设置LFO速率
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
rate: 速率 (Hz)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
return self.set_parameter(effect_id, 'rate', max(0.01, min(10.0, rate)))
|
|
|
|
def set_depth(self, effect_id: str, depth: float) -> bool:
|
|
"""
|
|
设置深度
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
depth: 深度 (0.0-1.0)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
return self.set_parameter(effect_id, 'depth', max(0.0, min(1.0, depth)))
|
|
|
|
def set_feedback(self, effect_id: str, feedback: float) -> bool:
|
|
"""
|
|
设置反馈
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
feedback: 反馈 (-1.0-1.0)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
return self.set_parameter(effect_id, 'feedback', max(-1.0, min(1.0, feedback)))
|
|
|
|
def set_mix(self, effect_id: str, mix: float) -> bool:
|
|
"""
|
|
设置湿信号混合
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
mix: 湿信号混合 (0.0-1.0)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
return self.set_parameter(effect_id, 'mix', max(0.0, min(1.0, mix)))
|
|
|
|
def set_delay(self, effect_id: str, delay: float) -> bool:
|
|
"""
|
|
设置延迟时间
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
delay: 延迟时间 (秒)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
return self.set_parameter(effect_id, 'delay', max(0.0001, min(0.05, delay)))
|
|
|
|
def set_center_delay(self, effect_id: str, delay: float) -> bool:
|
|
"""
|
|
设置中心延迟时间
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
delay: 中心延迟时间 (秒)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
return self.set_parameter(effect_id, 'center_delay', max(0.0001, min(0.05, delay)))
|
|
|
|
def set_spread(self, effect_id: str, spread: float) -> bool:
|
|
"""
|
|
设置扩散
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
spread: 扩散 (0.0-1.0)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
return self.set_parameter(effect_id, 'spread', max(0.0, min(1.0, spread)))
|
|
|
|
def set_lfo_waveform(self, effect_id: str, waveform: str) -> bool:
|
|
"""
|
|
设置LFO波形
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
waveform: 波形类型 (sine, triangle, square, sawtooth)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
valid_waveforms = ['sine', 'triangle', 'square', 'sawtooth']
|
|
if waveform not in valid_waveforms:
|
|
print(f"✗ 无效的LFO波形: {waveform}")
|
|
return False
|
|
|
|
return self.set_parameter(effect_id, 'lfo_waveform', waveform)
|
|
|
|
def enable_stereo(self, effect_id: str, enable: bool) -> bool:
|
|
"""
|
|
启用/禁用立体声
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
enable: 是否启用
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
return self.set_parameter(effect_id, 'stereo', enable)
|
|
|
|
def create_preset(self, preset_name: str) -> Dict[str, Any]:
|
|
"""
|
|
创建调制效果预设
|
|
|
|
Args:
|
|
preset_name: 预设名称
|
|
|
|
Returns:
|
|
预设参数字典
|
|
"""
|
|
presets = {
|
|
'chorus_light': {
|
|
'type': 'chorus',
|
|
'rate': 0.8,
|
|
'depth': 0.3,
|
|
'feedback': 0.2,
|
|
'mix': 0.4,
|
|
'center_delay': 0.004,
|
|
'spread': 0.3,
|
|
'lfo_waveform': 'sine'
|
|
},
|
|
'chorus_medium': {
|
|
'type': 'chorus',
|
|
'rate': 1.2,
|
|
'depth': 0.5,
|
|
'feedback': 0.3,
|
|
'mix': 0.6,
|
|
'center_delay': 0.006,
|
|
'spread': 0.5,
|
|
'lfo_waveform': 'sine'
|
|
},
|
|
'chorus_heavy': {
|
|
'type': 'chorus',
|
|
'rate': 1.8,
|
|
'depth': 0.7,
|
|
'feedback': 0.4,
|
|
'mix': 0.8,
|
|
'center_delay': 0.008,
|
|
'spread': 0.7,
|
|
'lfo_waveform': 'triangle'
|
|
},
|
|
'flanger_light': {
|
|
'type': 'flanger',
|
|
'rate': 0.5,
|
|
'depth': 0.4,
|
|
'feedback': 0.5,
|
|
'mix': 0.5,
|
|
'delay': 0.001,
|
|
'lfo_waveform': 'sine'
|
|
},
|
|
'flanger_medium': {
|
|
'type': 'flanger',
|
|
'rate': 0.8,
|
|
'depth': 0.6,
|
|
'feedback': 0.7,
|
|
'mix': 0.7,
|
|
'delay': 0.002,
|
|
'lfo_waveform': 'sine'
|
|
},
|
|
'flanger_heavy': {
|
|
'type': 'flanger',
|
|
'rate': 1.2,
|
|
'depth': 0.8,
|
|
'feedback': 0.9,
|
|
'mix': 0.9,
|
|
'delay': 0.003,
|
|
'lfo_waveform': 'triangle'
|
|
},
|
|
'phaser_light': {
|
|
'type': 'phaser',
|
|
'rate': 0.6,
|
|
'depth': 0.3,
|
|
'feedback': 0.2,
|
|
'mix': 0.4,
|
|
'delay': 0.0005,
|
|
'lfo_waveform': 'sine',
|
|
'high_cut': 6000.0,
|
|
'low_cut': 200.0
|
|
},
|
|
'phaser_medium': {
|
|
'type': 'phaser',
|
|
'rate': 1.0,
|
|
'depth': 0.5,
|
|
'feedback': 0.4,
|
|
'mix': 0.6,
|
|
'delay': 0.001,
|
|
'lfo_waveform': 'sine',
|
|
'high_cut': 8000.0,
|
|
'low_cut': 100.0
|
|
},
|
|
'phaser_heavy': {
|
|
'type': 'phaser',
|
|
'rate': 1.5,
|
|
'depth': 0.7,
|
|
'feedback': 0.6,
|
|
'mix': 0.8,
|
|
'delay': 0.002,
|
|
'lfo_waveform': 'triangle',
|
|
'high_cut': 10000.0,
|
|
'low_cut': 50.0
|
|
}
|
|
}
|
|
|
|
return presets.get(preset_name, {}).copy()
|
|
|
|
def get_lfo_meter(self, effect_id: str) -> float:
|
|
"""
|
|
获取LFO表
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
|
|
Returns:
|
|
当前LFO值 (-1.0 到 1.0)
|
|
"""
|
|
if effect_id not in self.effects:
|
|
return 0.0
|
|
|
|
effect = self.effects[effect_id]
|
|
parameters = effect['parameters']
|
|
lfo_waveform = parameters.get('lfo_waveform', 'sine')
|
|
lfo_phase = effect.get('lfo_phase', 0.0)
|
|
|
|
return self._generate_lfo_value(lfo_waveform, lfo_phase)
|
|
|
|
def set_lfo_phase(self, effect_id: str, phase: float) -> bool:
|
|
"""
|
|
设置LFO相位
|
|
|
|
Args:
|
|
effect_id: 效果ID
|
|
phase: 相位 (度)
|
|
|
|
Returns:
|
|
是否设置成功
|
|
"""
|
|
# 转换为弧度并规范化
|
|
phase_rad = (phase * math.pi / 180.0) % (2.0 * math.pi)
|
|
return self.set_parameter(effect_id, 'lfo_phase', phase)
|
|
|