EG/plugins/user/audio_reverb_effects/effects/spatial_processor.py
2025-12-12 16:16:15 +08:00

981 lines
34 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
空间音频效果处理器
实现专业的3D空间音频效果处理
"""
import uuid
import math
import numpy as np
from typing import Dict, List, Any, Optional, Tuple
from panda3d.core import Vec3
class SpatialProcessor:
"""
空间音频效果处理器
实现专业的3D空间音频效果处理
"""
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 # 默认采样率
self.speed_of_sound = 343.0 # 声速 (米/秒)
def create_effect(self, parameters: Dict[str, Any]) -> str:
"""
创建空间音频效果
Args:
parameters: 空间音频效果参数
Returns:
效果ID
"""
try:
# 生成唯一ID
effect_id = str(uuid.uuid4())
# 默认参数
default_params = {
'source_position': (0.0, 0.0, 0.0), # 音源位置 (x, y, z)
'listener_position': (0.0, 0.0, 0.0), # 听者位置 (x, y, z)
'listener_orientation': (0.0, 0.0, 0.0), # 听者方向 (heading, pitch, roll)
'min_distance': 1.0, # 最小距离
'max_distance': 100.0, # 最大距离
'rolloff_factor': 1.0, # 衰减因子
'cone_inner_angle': 360.0, # 内锥角 (度)
'cone_outer_angle': 360.0, # 外锥角 (度)
'cone_outer_gain': 1.0, # 外锥增益
'doppler_factor': 1.0, # 多普勒因子
'spread': 0.0, # 扩散角度 (度)
'air_absorption': 0.0, # 空气吸收
'room_rolloff': 0.0, # 房间衰减
'occlusion': 0.0, # 遮挡 (0.0-1.0)
'obstruction': 0.0, # 阻挡 (0.0-1.0)
'hrtf_enabled': False, # HRTF启用
'reverb_send': 0.0 # 混响发送 (0.0-1.0)
}
# 合并参数
effect_params = default_params.copy()
effect_params.update(parameters)
# 创建效果对象
effect = {
'id': effect_id,
'type': 'spatial',
'parameters': effect_params,
'active': True,
'buffers': {}, # 缓冲区
'hrtf_filters': {}, # HRTF滤波器
'distance': 0.0, # 当前距离
'azimuth': 0.0, # 方位角
'elevation': 0.0, # 仰角
'created_time': self._get_current_time(),
'process_count': 0
}
# 初始化缓冲区
self._initialize_buffers(effect)
# 初始化HRTF滤波器
if effect_params.get('hrtf_enabled', False):
self._initialize_hrtf_filters(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']
buffers = {}
# 输入和输出缓冲区
buffers['input'] = np.zeros(self.buffer_size)
buffers['output_left'] = np.zeros(self.buffer_size)
buffers['output_right'] = np.zeros(self.buffer_size)
# 延迟缓冲区(用于多普勒效应)
buffers['delay_line'] = np.zeros(int(0.1 * self.sample_rate)) # 100ms延迟线
buffers['delay_index'] = 0
effect['buffers'] = buffers
def _initialize_hrtf_filters(self, effect: Dict[str, Any]):
"""
初始化HRTF滤波器
Args:
effect: 效果对象
"""
# 这里应该加载真实的HRTF数据
# 简化实现使用生成的滤波器
hrtf_filters = {}
# 为不同的角度生成简化的HRTF滤波器
for azimuth in range(-180, 181, 15): # 每15度一个滤波器
for elevation in range(-90, 91, 15):
# 生成简化的HRTF滤波器系数
left_filter = self._generate_simple_hrtf_filter(azimuth, elevation, 'left')
right_filter = self._generate_simple_hrtf_filter(azimuth, elevation, 'right')
hrtf_filters[(azimuth, elevation)] = {
'left': left_filter,
'right': right_filter
}
effect['hrtf_filters'] = hrtf_filters
def _generate_simple_hrtf_filter(self, azimuth: int, elevation: int, channel: str) -> np.ndarray:
"""
生成简化的HRTF滤波器
Args:
azimuth: 方位角 (度)
elevation: 仰角 (度)
channel: 声道 ('left''right')
Returns:
滤波器系数数组
"""
# 简化的HRTF滤波器生成
# 实际应用中会使用真实的HRTF测量数据
# 滤波器长度
filter_length = 64
# 生成基于角度的简化的滤波器
filter_coeffs = np.zeros(filter_length)
# 基于角度计算延迟和幅度
if channel == 'left':
# 左耳滤波器
delay = max(0, int((1.0 - math.cos(math.radians(azimuth))) * 10))
amplitude = 0.5 + 0.5 * math.cos(math.radians(azimuth))
else:
# 右耳滤波器
delay = max(0, int((1.0 - math.cos(math.radians(-azimuth))) * 10))
amplitude = 0.5 + 0.5 * math.cos(math.radians(-azimuth))
# 应用延迟和幅度
if delay < filter_length:
filter_coeffs[delay] = amplitude
return filter_coeffs
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:
处理后的音频数据
"""
# 获取参数
source_pos = Vec3(*parameters.get('source_position', (0.0, 0.0, 0.0)))
listener_pos = Vec3(*parameters.get('listener_position', (0.0, 0.0, 0.0)))
listener_orient = parameters.get('listener_orientation', (0.0, 0.0, 0.0))
min_distance = max(0.1, parameters.get('min_distance', 1.0))
max_distance = max(min_distance, parameters.get('max_distance', 100.0))
rolloff_factor = max(0.0, parameters.get('rolloff_factor', 1.0))
cone_inner_angle = max(0.0, min(360.0, parameters.get('cone_inner_angle', 360.0)))
cone_outer_angle = max(cone_inner_angle, min(360.0, parameters.get('cone_outer_angle', 360.0)))
cone_outer_gain = max(0.0, min(1.0, parameters.get('cone_outer_gain', 1.0)))
doppler_factor = max(0.0, parameters.get('doppler_factor', 1.0))
spread = max(0.0, parameters.get('spread', 0.0))
air_absorption = max(0.0, parameters.get('air_absorption', 0.0))
occlusion = max(0.0, min(1.0, parameters.get('occlusion', 0.0)))
obstruction = max(0.0, min(1.0, parameters.get('obstruction', 0.0)))
hrtf_enabled = parameters.get('hrtf_enabled', False)
reverb_send = max(0.0, min(1.0, parameters.get('reverb_send', 0.0)))
# 计算距离
distance = (source_pos - listener_pos).length()
# 计算方位角和仰角
azimuth, elevation = self._calculate_angles(source_pos, listener_pos, listener_orient)
# 计算音量衰减
volume = self._calculate_volume_attenuation(
distance, min_distance, max_distance, rolloff_factor)
# 计算锥形效应
cone_gain = self._calculate_cone_gain(
source_pos, listener_pos, listener_orient,
cone_inner_angle, cone_outer_angle, cone_outer_gain)
# 计算遮挡和阻挡
occlusion_gain = 1.0 - occlusion * 0.8 # 最多减少80%音量
obstruction_gain = 1.0 - obstruction * 0.5 # 最多减少50%音量
# 计算多普勒效应
doppler_shift = self._calculate_doppler_shift(
source_pos, listener_pos, doppler_factor)
# 计算空气吸收
air_absorption_gain = 1.0 - (distance / max_distance) * air_absorption * 0.5
# 综合增益
total_gain = (volume * cone_gain * occlusion_gain *
obstruction_gain * air_absorption_gain)
# 创建输出数组
if audio_data.ndim == 1:
# 单声道输入,生成立体声输出
output_left = np.zeros_like(audio_data)
output_right = np.zeros_like(audio_data)
for i in range(len(audio_data)):
sample = audio_data[i]
# 应用增益
processed_sample = sample * total_gain
# 应用HRTF或简单立体声处理
if hrtf_enabled:
# 简化的HRTF应用
left_sample, right_sample = self._apply_hrtf(
processed_sample, azimuth, elevation)
else:
# 简单的立体声平移
left_sample, right_sample = self._simple_stereo_pan(
processed_sample, azimuth, spread)
output_left[i] = left_sample
output_right[i] = right_sample
# 合并为立体声数组
output_data = np.array([output_left, output_right])
else:
# 多声道处理
if audio_data.shape[0] >= 2:
# 已经是立体声,应用空间效果
output_left = np.zeros_like(audio_data[0])
output_right = np.zeros_like(audio_data[1])
for i in range(audio_data.shape[1]):
left_sample = audio_data[0, i] * total_gain
right_sample = audio_data[1, i] * total_gain
# 应用HRTF或简单立体声处理
if hrtf_enabled:
# 简化的HRTF应用
new_left, new_right = self._apply_hrtf(
(left_sample + right_sample) * 0.5, azimuth, elevation)
output_left[i] = new_left
output_right[i] = new_right
else:
# 简单的立体声平移
new_left, new_right = self._simple_stereo_pan(
(left_sample + right_sample) * 0.5, azimuth, spread)
output_left[i] = new_left
output_right[i] = new_right
output_data = np.array([output_left, output_right])
else:
# 其他多声道情况,返回原始数据
output_data = audio_data
# 确保输出在有效范围内
processed_data = np.clip(output_data, -1.0, 1.0)
return processed_data
def _calculate_angles(self, source_pos: Vec3, listener_pos: Vec3,
listener_orient: Tuple[float, float, float]) -> Tuple[float, float]:
"""
计算方位角和仰角
Args:
source_pos: 音源位置
listener_pos: 听者位置
listener_orient: 听者方向
Returns:
(方位角, 仰角) (度)
"""
# 计算相对位置
relative_pos = source_pos - listener_pos
# 计算方位角 (水平角度)
azimuth = math.degrees(math.atan2(relative_pos.x, -relative_pos.y))
# 计算仰角 (垂直角度)
distance_xy = math.sqrt(relative_pos.x**2 + relative_pos.y**2)
elevation = math.degrees(math.atan2(relative_pos.z, distance_xy))
return azimuth, elevation
def _calculate_volume_attenuation(self, distance: float, min_distance: float,
max_distance: float, rolloff_factor: float) -> float:
"""
计算音量衰减
Args:
distance: 距离
min_distance: 最小距离
max_distance: 最大距离
rolloff_factor: 衰减因子
Returns:
音量增益 (0.0-1.0)
"""
if distance <= min_distance:
return 1.0
elif distance >= max_distance:
return 0.0
else:
# 反距离衰减模型
gain = min_distance / (min_distance + rolloff_factor * (distance - min_distance))
return max(0.0, min(1.0, gain))
def _calculate_cone_gain(self, source_pos: Vec3, listener_pos: Vec3,
listener_orient: Tuple[float, float, float],
inner_angle: float, outer_angle: float, outer_gain: float) -> float:
"""
计算锥形效应增益
Args:
source_pos: 音源位置
listener_pos: 听者位置
listener_orient: 听者方向
inner_angle: 内锥角 (度)
outer_angle: 外锥角 (度)
outer_gain: 外锥增益
Returns:
锥形增益 (0.0-1.0)
"""
# 简化的锥形效应计算
# 实际应用中需要考虑音源的朝向
if inner_angle >= 360.0 and outer_angle >= 360.0:
return 1.0
# 计算听者相对于音源的角度
relative_pos = listener_pos - source_pos
angle = math.degrees(math.acos(relative_pos.normalized().dot(Vec3(0, -1, 0))))
if angle <= inner_angle / 2.0:
return 1.0
elif angle >= outer_angle / 2.0:
return outer_gain
else:
# 线性插值
t = (angle - inner_angle / 2.0) / (outer_angle / 2.0 - inner_angle / 2.0)
return 1.0 - t * (1.0 - outer_gain)
def _calculate_doppler_shift(self, source_pos: Vec3, listener_pos: Vec3,
doppler_factor: float) -> float:
"""
计算多普勒频移
Args:
source_pos: 音源位置
listener_pos: 听者位置
doppler_factor: 多普勒因子
Returns:
频移比率
"""
# 简化的多普勒效应计算
# 实际应用中需要考虑音源和听者的速度
if doppler_factor <= 0.0:
return 1.0
# 计算相对速度(简化为距离变化率)
relative_velocity = (source_pos - listener_pos).length() / self.sample_rate
ratio = (self.speed_of_sound - doppler_factor * relative_velocity) / self.speed_of_sound
return max(0.5, min(2.0, ratio))
def _apply_hrtf(self, sample: float, azimuth: float, elevation: float) -> Tuple[float, float]:
"""
应用HRTF
Args:
sample: 输入样本
azimuth: 方位角 (度)
elevation: 仰角 (度)
Returns:
(左声道样本, 右声道样本)
"""
# 简化的HRTF应用
# 实际应用中会使用真实的HRTF滤波器
# 量化角度以匹配预生成的滤波器
azimuth_quantized = int(round(azimuth / 15.0)) * 15
elevation_quantized = int(round(elevation / 15.0)) * 15
# 限制角度范围
azimuth_quantized = max(-180, min(180, azimuth_quantized))
elevation_quantized = max(-90, min(90, elevation_quantized))
# 简化的HRTF效果
left_gain = 0.5 + 0.5 * math.cos(math.radians(azimuth))
right_gain = 0.5 + 0.5 * math.cos(math.radians(-azimuth))
# 应用仰角影响
elevation_factor = math.cos(math.radians(elevation))
left_gain *= elevation_factor
right_gain *= elevation_factor
return sample * left_gain, sample * right_gain
def _simple_stereo_pan(self, sample: float, azimuth: float, spread: float) -> Tuple[float, float]:
"""
简单的立体声平移
Args:
sample: 输入样本
azimuth: 方位角 (度)
spread: 扩散角度
Returns:
(左声道样本, 右声道样本)
"""
# 将角度转换为-1到1的平移值
pan = math.sin(math.radians(azimuth))
# 应用扩散
if spread > 0:
spread_factor = 1.0 - spread / 180.0
pan *= spread_factor
# 计算左右声道增益
left_gain = 0.5 - 0.5 * pan
right_gain = 0.5 + 0.5 * pan
return sample * left_gain, sample * right_gain
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
# 如果HRTF启用状态改变重新初始化滤波器
if parameter == 'hrtf_enabled':
if value:
self._initialize_hrtf_filters(self.effects[effect_id])
else:
self.effects[effect_id]['hrtf_filters'] = {}
# 如果是插件中的效果,也更新插件中的副本
if self.plugin and effect_id in self.plugin.effects:
self.plugin.effects[effect_id]['parameters'][parameter] = value
if parameter == 'hrtf_enabled':
self.plugin.effects[effect_id]['hrtf_filters'] = \
self.effects[effect_id]['hrtf_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.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_source_position(self, effect_id: str, position: Tuple[float, float, float]) -> bool:
"""
设置音源位置
Args:
effect_id: 效果ID
position: 位置 (x, y, z)
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'source_position', position)
def set_listener_position(self, effect_id: str, position: Tuple[float, float, float]) -> bool:
"""
设置听者位置
Args:
effect_id: 效果ID
position: 位置 (x, y, z)
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'listener_position', position)
def set_listener_orientation(self, effect_id: str, orientation: Tuple[float, float, float]) -> bool:
"""
设置听者方向
Args:
effect_id: 效果ID
orientation: 方向 (heading, pitch, roll)
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'listener_orientation', orientation)
def set_distance_model(self, effect_id: str, min_distance: float,
max_distance: float, rolloff_factor: float) -> bool:
"""
设置距离模型参数
Args:
effect_id: 效果ID
min_distance: 最小距离
max_distance: 最大距离
rolloff_factor: 衰减因子
Returns:
是否设置成功
"""
success = True
success &= self.set_parameter(effect_id, 'min_distance', max(0.1, min_distance))
success &= self.set_parameter(effect_id, 'max_distance', max(min_distance, max_distance))
success &= self.set_parameter(effect_id, 'rolloff_factor', max(0.0, rolloff_factor))
return success
def set_cone_effect(self, effect_id: str, inner_angle: float,
outer_angle: float, outer_gain: float) -> bool:
"""
设置锥形效应参数
Args:
effect_id: 效果ID
inner_angle: 内锥角 (度)
outer_angle: 外锥角 (度)
outer_gain: 外锥增益
Returns:
是否设置成功
"""
success = True
success &= self.set_parameter(effect_id, 'cone_inner_angle', max(0.0, min(360.0, inner_angle)))
success &= self.set_parameter(effect_id, 'cone_outer_angle', max(inner_angle, min(360.0, outer_angle)))
success &= self.set_parameter(effect_id, 'cone_outer_gain', max(0.0, min(1.0, outer_gain)))
return success
def set_doppler_factor(self, effect_id: str, factor: float) -> bool:
"""
设置多普勒因子
Args:
effect_id: 效果ID
factor: 多普勒因子
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'doppler_factor', max(0.0, factor))
def set_spread(self, effect_id: str, spread: float) -> bool:
"""
设置扩散角度
Args:
effect_id: 效果ID
spread: 扩散角度 (度)
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'spread', max(0.0, spread))
def set_air_absorption(self, effect_id: str, absorption: float) -> bool:
"""
设置空气吸收
Args:
effect_id: 效果ID
absorption: 空气吸收系数
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'air_absorption', max(0.0, min(1.0, absorption)))
def set_occlusion(self, effect_id: str, occlusion: float) -> bool:
"""
设置遮挡系数
Args:
effect_id: 效果ID
occlusion: 遮挡系数 (0.0-1.0)
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'occlusion', max(0.0, min(1.0, occlusion)))
def set_obstruction(self, effect_id: str, obstruction: float) -> bool:
"""
设置阻挡系数
Args:
effect_id: 效果ID
obstruction: 阻挡系数 (0.0-1.0)
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'obstruction', max(0.0, min(1.0, obstruction)))
def enable_hrtf(self, effect_id: str, enable: bool) -> bool:
"""
启用/禁用HRTF
Args:
effect_id: 效果ID
enable: 是否启用
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'hrtf_enabled', enable)
def set_reverb_send(self, effect_id: str, send: float) -> bool:
"""
设置混响发送量
Args:
effect_id: 效果ID
send: 混响发送量 (0.0-1.0)
Returns:
是否设置成功
"""
return self.set_parameter(effect_id, 'reverb_send', max(0.0, min(1.0, send)))
def get_distance(self, effect_id: str) -> float:
"""
获取当前距离
Args:
effect_id: 效果ID
Returns:
距离值
"""
if effect_id not in self.effects:
return 0.0
return self.effects[effect_id].get('distance', 0.0)
def get_angles(self, effect_id: str) -> Tuple[float, float]:
"""
获取当前角度
Args:
effect_id: 效果ID
Returns:
(方位角, 仰角) (度)
"""
if effect_id not in self.effects:
return (0.0, 0.0)
effect = self.effects[effect_id]
return (effect.get('azimuth', 0.0), effect.get('elevation', 0.0))
def create_preset(self, preset_name: str) -> Dict[str, Any]:
"""
创建空间音频效果预设
Args:
preset_name: 预设名称
Returns:
预设参数字典
"""
presets = {
'close': {
'min_distance': 0.5,
'max_distance': 20.0,
'rolloff_factor': 1.0,
'doppler_factor': 1.0,
'air_absorption': 0.0
},
'medium': {
'min_distance': 1.0,
'max_distance': 50.0,
'rolloff_factor': 0.8,
'doppler_factor': 0.8,
'air_absorption': 0.1
},
'far': {
'min_distance': 5.0,
'max_distance': 100.0,
'rolloff_factor': 0.5,
'doppler_factor': 0.5,
'air_absorption': 0.3
},
'outdoor': {
'min_distance': 2.0,
'max_distance': 200.0,
'rolloff_factor': 0.3,
'doppler_factor': 1.0,
'air_absorption': 0.5
},
'indoor': {
'min_distance': 0.5,
'max_distance': 30.0,
'rolloff_factor': 1.2,
'doppler_factor': 0.7,
'air_absorption': 0.0
},
'underwater': {
'min_distance': 1.0,
'max_distance': 40.0,
'rolloff_factor': 0.2,
'doppler_factor': 0.3,
'air_absorption': 0.8,
'speed_of_sound': 1500.0 # 水中声速
}
}
return presets.get(preset_name, {}).copy()