""" 3D空间音效插件主文件 提供基于Panda3D的3D音频处理功能,支持空间音效、环境音效和音频效果处理 """ import math from typing import Dict, List, Optional, Any from plugins.plugin_manager import BasePlugin from panda3d.core import AudioSound, NodePath from direct.showbase.AudioManager import AudioManager class Plugin(BasePlugin): """ 3D空间音效插件 提供基于Panda3D的3D音频处理功能 """ def __init__(self, plugin_manager, name): super().__init__(plugin_manager, name) self.config = { "version": "1.0.0", "author": "EG Team", "description": "3D空间音效插件,支持3D定位音频、环境音效和音频效果处理" } # 核心组件 self.audio_manager = None self.sound_sources = {} # 音频源管理 self.listener = None # 听者节点 self.audio_effects = {} # 音频效果管理 self.environment_zones = {} # 环境区域管理 # GUI元素 self.gui_elements = [] # 事件处理器 self.event_handlers = {} # 插件状态 self.is_initialized = False self.is_enabled = False # 性能监控 self.performance_stats = { 'active_sounds': 0, 'total_sounds': 0, 'effects_applied': 0 } def initialize(self) -> bool: """ 初始化插件 """ try: if self.is_initialized: return True print(f"初始化3D空间音效插件: {self.name}") # 初始化音频管理器 self.audio_manager = self.plugin_manager.world.audio_manager # 初始化听者 self.listener = self.plugin_manager.world.camera # 初始化音频源管理器 from .core.audio_source_manager import AudioSourceManager self.audio_source_manager = AudioSourceManager(self) # 初始化音频效果处理器 from .effects.audio_effect_processor import AudioEffectProcessor self.audio_effect_processor = AudioEffectProcessor(self) # 初始化环境音频管理器 from .core.environment_audio import EnvironmentAudioManager self.environment_audio_manager = EnvironmentAudioManager(self) self.is_initialized = True print("✓ 3D空间音效插件初始化完成") return True except Exception as e: print(f"✗ 3D空间音效插件初始化失败: {e}") import traceback traceback.print_exc() return False def enable(self) -> bool: """ 启用插件 """ if not super().enable(): return False if self.is_enabled: return True try: print(f"启用3D空间音效插件: {self.name}") # 注册事件处理器 self._register_event_handlers() # 创建GUI界面 self._create_gui() self.is_enabled = True print("✓ 3D空间音效插件启用成功") return True except Exception as e: print(f"✗ 3D空间音效插件启用失败: {e}") import traceback traceback.print_exc() return False def disable(self) -> bool: """ 禁用插件 """ if not super().disable(): return False if not self.is_enabled: return True try: print(f"禁用3D空间音效插件: {self.name}") # 清理GUI界面 self._cleanup_gui() # 移除事件处理器 self._unregister_event_handlers() # 停止所有音频 self.stop_all_sounds() self.is_enabled = False print("✓ 3D空间音效插件禁用成功") return True except Exception as e: print(f"✗ 3D空间音效插件禁用失败: {e}") import traceback traceback.print_exc() return False def finalize(self): """ 清理插件资源 """ print(f"清理3D空间音效插件资源: {self.name}") # 停止所有音频 self.stop_all_sounds() # 清理所有组件 if self.audio_source_manager: self.audio_source_manager.cleanup() self.audio_source_manager = None if self.audio_effect_processor: self.audio_effect_processor.cleanup() self.audio_effect_processor = None if self.environment_audio_manager: self.environment_audio_manager.cleanup() self.environment_audio_manager = None self.audio_manager = None self.listener = None self.sound_sources.clear() self.audio_effects.clear() self.environment_zones.clear() self.is_initialized = False self.is_enabled = False def _register_event_handlers(self): """ 注册事件处理器 """ world = self.plugin_manager.world # 3D音频系统控制快捷键 self.event_handlers['f1'] = self.toggle_audio_debug self.event_handlers['f2'] = self.toggle_spatial_audio self.event_handlers['f3'] = self.play_test_sound self.event_handlers['f4'] = self.stop_all_sounds self.event_handlers['f5'] = self.show_audio_stats self.event_handlers['f6'] = self.toggle_environment_audio self.event_handlers['f7'] = self.apply_reverb_effect self.event_handlers['f8'] = self.apply_echo_effect # 注册事件 for event, handler in self.event_handlers.items(): world.accept(event, handler) world.accept(event.upper(), handler) # 同时注册大写事件 def _unregister_event_handlers(self): """ 移除事件处理器 """ world = self.plugin_manager.world for event in self.event_handlers.keys(): world.ignore(event) world.ignore(event.upper()) self.event_handlers.clear() def _create_gui(self): """ 创建GUI界面 """ try: world = self.plugin_manager.world # 检查是否有GUI管理器 if not hasattr(world, 'gui_manager') or not world.gui_manager: print("⚠ GUI管理器不可用,跳过GUI创建") return gui_manager = world.gui_manager # 创建3D音频控制面板 panel_button = gui_manager.createGUIButton( pos=(0.02, 0, 0.35), text="3D音频", size=0.06 ) self.gui_elements.append(panel_button) # 创建功能按钮 functions = [ ("音频调试 [F1]", self.toggle_audio_debug), ("空间音频 [F2]", self.toggle_spatial_audio), ("测试音效 [F3]", self.play_test_sound), ("停止音频 [F4]", self.stop_all_sounds), ("音频统计 [F5]", self.show_audio_stats), ("环境音频 [F6]", self.toggle_environment_audio), ("混响效果 [F7]", self.apply_reverb_effect), ("回声效果 [F8]", self.apply_echo_effect) ] for i, (name, callback) in enumerate(functions): button = gui_manager.createGUIButton( pos=(0.02, 0, 0.28 - i * 0.055), text=name, size=0.045 ) self.gui_elements.append(button) world.accept(f"audio_function_{name}", callback) except Exception as e: print(f"⚠ GUI创建失败: {e}") def _cleanup_gui(self): """ 清理GUI界面 """ try: world = self.plugin_manager.world if hasattr(world, 'gui_manager') and world.gui_manager: gui_manager = world.gui_manager # 删除所有GUI元素 for element in self.gui_elements: gui_manager.deleteGUIElement(element) self.gui_elements.clear() except Exception as e: print(f"⚠ GUI清理失败: {e}") # 事件处理方法 def toggle_audio_debug(self): """切换音频调试模式""" print("✓ 音频调试模式切换") def toggle_spatial_audio(self): """切换空间音频""" print("✓ 空间音频切换") def play_test_sound(self): """播放测试音效""" print("✓ 播放测试音效") def stop_all_sounds(self): """停止所有音频""" if self.audio_source_manager: self.audio_source_manager.stop_all_sounds() print("✓ 停止所有音频") def show_audio_stats(self): """显示音频统计信息""" stats = self.get_stats() print("=== 3D音频统计信息 ===") for key, value in stats.items(): print(f" {key}: {value}") def toggle_environment_audio(self): """切换环境音频""" if self.environment_audio_manager: self.environment_audio_manager.toggle_enabled() print("✓ 环境音频切换") def apply_reverb_effect(self): """应用混响效果""" print("✓ 应用混响效果") def apply_echo_effect(self): """应用回声效果""" print("✓ 应用回声效果") def get_stats(self) -> Dict[str, Any]: """ 获取插件统计信息 Returns: 统计信息字典 """ stats = self.performance_stats.copy() if self.audio_source_manager: stats.update(self.audio_source_manager.get_stats()) if self.audio_effect_processor: stats.update(self.audio_effect_processor.get_stats()) if self.environment_audio_manager: stats.update(self.environment_audio_manager.get_stats()) return stats # 公共接口方法 def create_3d_sound(self, filepath: str, position: tuple = (0, 0, 0), loop: bool = False, volume: float = 1.0) -> Optional[str]: """ 创建3D音效 Args: filepath: 音频文件路径 position: 音源位置 (x, y, z) loop: 是否循环播放 volume: 音量 (0.0-1.0) Returns: 音源ID,如果创建失败则返回None """ if self.audio_source_manager: return self.audio_source_manager.create_3d_sound(filepath, position, loop, volume) return None def create_2d_sound(self, filepath: str, loop: bool = False, volume: float = 1.0) -> Optional[str]: """ 创建2D音效 Args: filepath: 音频文件路径 loop: 是否循环播放 volume: 音量 (0.0-1.0) Returns: 音源ID,如果创建失败则返回None """ if self.audio_source_manager: return self.audio_source_manager.create_2d_sound(filepath, loop, volume) return None def play_sound(self, sound_id: str) -> bool: """ 播放音效 Args: sound_id: 音源ID Returns: 是否播放成功 """ if self.audio_source_manager: return self.audio_source_manager.play_sound(sound_id) return False def stop_sound(self, sound_id: str) -> bool: """ 停止音效 Args: sound_id: 音源ID Returns: 是否停止成功 """ if self.audio_source_manager: return self.audio_source_manager.stop_sound(sound_id) return False def pause_sound(self, sound_id: str) -> bool: """ 暂停音效 Args: sound_id: 音源ID Returns: 是否暂停成功 """ if self.audio_source_manager: return self.audio_source_manager.pause_sound(sound_id) return False def resume_sound(self, sound_id: str) -> bool: """ 恢复音效 Args: sound_id: 音源ID Returns: 是否恢复成功 """ if self.audio_source_manager: return self.audio_source_manager.resume_sound(sound_id) return False def set_sound_position(self, sound_id: str, position: tuple) -> bool: """ 设置音源位置 Args: sound_id: 音源ID position: 位置 (x, y, z) Returns: 是否设置成功 """ if self.audio_source_manager: return self.audio_source_manager.set_sound_position(sound_id, position) return False def set_sound_volume(self, sound_id: str, volume: float) -> bool: """ 设置音源音量 Args: sound_id: 音源ID volume: 音量 (0.0-1.0) Returns: 是否设置成功 """ if self.audio_source_manager: return self.audio_source_manager.set_sound_volume(sound_id, volume) return False def set_sound_loop(self, sound_id: str, loop: bool) -> bool: """ 设置音源循环模式 Args: sound_id: 音源ID loop: 是否循环 Returns: 是否设置成功 """ if self.audio_source_manager: return self.audio_source_manager.set_sound_loop(sound_id, loop) return False def is_sound_playing(self, sound_id: str) -> bool: """ 检查音效是否正在播放 Args: sound_id: 音源ID Returns: 是否正在播放 """ if self.audio_source_manager: return self.audio_source_manager.is_sound_playing(sound_id) return False def get_sound_duration(self, sound_id: str) -> float: """ 获取音效时长 Args: sound_id: 音源ID Returns: 音效时长(秒) """ if self.audio_source_manager: return self.audio_source_manager.get_sound_duration(sound_id) return 0.0 def get_sound_position(self, sound_id: str) -> tuple: """ 获取音源位置 Args: sound_id: 音源ID Returns: 音源位置 (x, y, z) """ if self.audio_source_manager: return self.audio_source_manager.get_sound_position(sound_id) return (0, 0, 0) def delete_sound(self, sound_id: str) -> bool: """ 删除音效 Args: sound_id: 音源ID Returns: 是否删除成功 """ if self.audio_source_manager: return self.audio_source_manager.delete_sound(sound_id) return False def create_audio_effect(self, effect_type: str, parameters: Dict[str, Any]) -> str: """ 创建音频效果 Args: effect_type: 效果类型 parameters: 效果参数 Returns: 效果ID """ if self.audio_effect_processor: return self.audio_effect_processor.create_effect(effect_type, parameters) return "" def apply_effect_to_sound(self, sound_id: str, effect_id: str) -> bool: """ 应用效果到音效 Args: sound_id: 音源ID effect_id: 效果ID Returns: 是否应用成功 """ if self.audio_effect_processor: return self.audio_effect_processor.apply_effect_to_sound(sound_id, effect_id) return False def remove_effect_from_sound(self, sound_id: str, effect_id: str) -> bool: """ 从音效移除效果 Args: sound_id: 音源ID effect_id: 效果ID Returns: 是否移除成功 """ if self.audio_effect_processor: return self.audio_effect_processor.remove_effect_from_sound(sound_id, effect_id) return False def set_listener_position(self, position: tuple) -> bool: """ 设置听者位置 Args: position: 位置 (x, y, z) Returns: 是否设置成功 """ if self.listener: self.listener.setPos(position[0], position[1], position[2]) return True return False def set_listener_orientation(self, orientation: tuple) -> bool: """ 设置听者方向 Args: orientation: 方向 (heading, pitch, roll) Returns: 是否设置成功 """ if self.listener: self.listener.setHpr(orientation[0], orientation[1], orientation[2]) return True return False def create_environment_zone(self, zone_id: str, position: tuple, radius: float, properties: Dict[str, Any]) -> bool: """ 创建环境区域 Args: zone_id: 区域ID position: 位置 (x, y, z) radius: 半径 properties: 区域属性 Returns: 是否创建成功 """ if self.environment_audio_manager: return self.environment_audio_manager.create_zone(zone_id, position, radius, properties) return False def set_zone_property(self, zone_id: str, property_name: str, value: Any) -> bool: """ 设置区域属性 Args: zone_id: 区域ID property_name: 属性名 value: 属性值 Returns: 是否设置成功 """ if self.environment_audio_manager: return self.environment_audio_manager.set_zone_property(zone_id, property_name, value) return False def update(self, dt: float): """ 更新插件状态 Args: dt: 时间增量 """ # 更新音频源管理器 if self.audio_source_manager: self.audio_source_manager.update(dt) # 更新环境音频管理器 if self.environment_audio_manager: self.environment_audio_manager.update(dt)