EG/plugins/user/weather_season_system/audio/audio_manager.py
2025-10-30 11:46:41 +08:00

650 lines
20 KiB
Python

"""
音频管理系统
负责管理天气和季节的音频效果,如环境音、天气音效等
"""
import time
import random
from typing import Dict, Any, List, Optional
import math
class AudioManager:
"""
音频管理系统
负责管理天气和季节的音频效果,包括环境音、天气音效、音频过渡等
"""
def __init__(self, plugin):
"""
初始化音频管理系统
Args:
plugin: 天气和季节系统插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 音频效果配置
self.audio_effects = {
'wind': {
'name': '风声',
'file': 'audio/wind.wav',
'volume_range': (0.1, 0.5),
'pitch_range': (0.8, 1.2),
'loop': True,
'fade_time': 2.0,
'priority': 1
},
'rain': {
'name': '雨声',
'file': 'audio/rain.wav',
'volume_range': (0.2, 0.7),
'pitch_range': (0.9, 1.1),
'loop': True,
'fade_time': 3.0,
'priority': 2
},
'thunderstorm': {
'name': '雷暴声',
'file': 'audio/thunderstorm.wav',
'volume_range': (0.3, 1.0),
'pitch_range': (0.7, 1.3),
'loop': True,
'fade_time': 4.0,
'priority': 3
},
'snow': {
'name': '雪声',
'file': 'audio/snow.wav',
'volume_range': (0.05, 0.3),
'pitch_range': (0.8, 1.0),
'loop': True,
'fade_time': 2.5,
'priority': 1
},
'hail': {
'name': '冰雹声',
'file': 'audio/hail.wav',
'volume_range': (0.2, 0.8),
'pitch_range': (0.9, 1.2),
'loop': True,
'fade_time': 2.0,
'priority': 2
},
'birds': {
'name': '鸟鸣声',
'file': 'audio/birds.wav',
'volume_range': (0.1, 0.4),
'pitch_range': (0.9, 1.1),
'loop': True,
'fade_time': 3.0,
'priority': 1
},
'crickets': {
'name': '蟋蟀声',
'file': 'audio/crickets.wav',
'volume_range': (0.1, 0.3),
'pitch_range': (0.8, 1.0),
'loop': True,
'fade_time': 2.5,
'priority': 1
},
'ocean': {
'name': '海浪声',
'file': 'audio/ocean.wav',
'volume_range': (0.2, 0.6),
'pitch_range': (0.9, 1.1),
'loop': True,
'fade_time': 3.5,
'priority': 1
}
}
# 当前播放的音频
self.active_audio = {}
# 环境音配置
self.ambient_sounds = {
'day_ambient': {
'name': '白天环境音',
'file': 'audio/day_ambient.wav',
'volume': 0.3,
'priority': 0
},
'night_ambient': {
'name': '夜晚环境音',
'file': 'audio/night_ambient.wav',
'volume': 0.2,
'priority': 0
}
}
# 音频过渡配置
self.transition_config = {
'crossfade_time': 2.0,
'max_concurrent_sounds': 5,
'distance_attenuation': True,
'occlusion_effect': True
}
# 音频参数
self.audio_parameters = {
'master_volume': 1.0,
'effects_volume': 1.0,
'ambient_volume': 1.0,
'music_volume': 1.0,
'doppler_effect': True,
'reverb_enabled': True
}
# 音频更新配置
self.update_interval = 0.1 # 更新间隔(秒)
self.last_update_time = 0.0
# 统计信息
self.stats = {
'sounds_played': 0,
'transitions_made': 0,
'sounds_stopped': 0,
'total_audio_time': 0.0
}
print("✓ 音频管理系统已创建")
def initialize(self) -> bool:
"""
初始化音频管理系统
Returns:
是否初始化成功
"""
try:
self.initialized = True
print("✓ 音频管理系统初始化完成")
return True
except Exception as e:
print(f"✗ 音频管理系统初始化失败: {e}")
import traceback
traceback.print_exc()
return False
def enable(self) -> bool:
"""
启用音频管理系统
Returns:
是否启用成功
"""
try:
if not self.initialized:
print("✗ 音频管理系统未初始化")
return False
self.enabled = True
print("✓ 音频管理系统已启用")
return True
except Exception as e:
print(f"✗ 音频管理系统启用失败: {e}")
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用音频管理系统"""
try:
self.enabled = False
self._stop_all_audio()
print("✓ 音频管理系统已禁用")
except Exception as e:
print(f"✗ 音频管理系统禁用失败: {e}")
import traceback
traceback.print_exc()
def finalize(self):
"""清理音频管理系统资源"""
try:
self.disable()
self.initialized = False
print("✓ 音频管理系统资源已清理")
except Exception as e:
print(f"✗ 音频管理系统资源清理失败: {e}")
import traceback
traceback.print_exc()
def update(self, dt: float):
"""
更新音频管理系统状态
Args:
dt: 时间增量
"""
try:
if not self.enabled:
return
# 更新计时器
self.last_update_time += dt
if self.last_update_time < self.update_interval:
return
# 重置更新计时器
self.last_update_time = 0.0
# 更新激活的音频
self._update_active_audio(dt)
# 根据当前天气和时间更新音频效果
self._update_weather_audio()
self._update_time_audio()
# 更新统计信息
self.stats['total_audio_time'] += dt
except Exception as e:
print(f"✗ 音频管理系统更新失败: {e}")
import traceback
traceback.print_exc()
def _update_active_audio(self, dt: float):
"""
更新激活的音频
Args:
dt: 时间增量
"""
try:
# 在实际实现中,这里会更新音频播放状态、音量淡入淡出等
pass
except Exception as e:
print(f"✗ 激活音频更新失败: {e}")
def _update_weather_audio(self):
"""根据当前天气更新音频效果"""
try:
if not self.plugin.weather_manager:
return
current_weather = self.plugin.weather_manager.get_current_weather()
weather_info = self.plugin.weather_manager.get_weather_info(current_weather)
if not weather_info:
return
# 获取天气对应的音频效果
audio_effect = weather_info.get('audio_effect')
# 检查是否需要激活或更新音频效果
if audio_effect and audio_effect in self.audio_effects:
# 检查效果是否已经激活
if audio_effect not in self.active_audio:
# 激活音频效果
self._play_audio_effect(audio_effect)
else:
# 更新现有音频效果的参数
self._update_audio_effect_parameters(audio_effect)
else:
# 检查是否需要停用音频效果
weather_effects = [
name for name in self.active_audio.keys()
if name in self.audio_effects and name != 'birds' and name != 'crickets'
]
for effect_name in weather_effects:
self._stop_audio_effect(effect_name)
except Exception as e:
print(f"✗ 天气音频更新失败: {e}")
def _update_time_audio(self):
"""根据当前时间更新环境音频"""
try:
if not self.plugin.environment_effects:
return
time_config = getattr(self.plugin.environment_effects, 'time_config', {'day_time': 12.0})
current_time = time_config.get('day_time', 12.0)
# 根据时间播放不同的环境音
if 6 <= current_time <= 18: # 白天
if 'night_ambient' in self.active_audio:
self._stop_audio_effect('night_ambient')
if 'day_ambient' not in self.active_audio:
self._play_ambient_sound('day_ambient')
else: # 夜晚
if 'day_ambient' in self.active_audio:
self._stop_audio_effect('day_ambient')
if 'night_ambient' not in self.active_audio:
self._play_ambient_sound('night_ambient')
except Exception as e:
print(f"✗ 时间音频更新失败: {e}")
def _play_audio_effect(self, effect_name: str):
"""
播放音频效果
Args:
effect_name: 音频效果名称
"""
try:
if effect_name not in self.audio_effects:
return
effect_config = self.audio_effects[effect_name]
# 创建音频数据
audio_data = {
'name': effect_config['name'],
'file': effect_config['file'],
'config': effect_config,
'start_time': time.time(),
'volume': effect_config['volume_range'][0],
'target_volume': effect_config['volume_range'][1],
'state': 'fading_in', # 'fading_in', 'playing', 'fading_out'
'fade_progress': 0.0
}
# 添加到激活音频列表
self.active_audio[effect_name] = audio_data
# 更新统计信息
self.stats['sounds_played'] += 1
print(f"✓ 音频效果开始播放: {effect_config['name']}")
except Exception as e:
print(f"✗ 音频效果播放失败: {e}")
def _play_ambient_sound(self, sound_name: str):
"""
播放环境音
Args:
sound_name: 环境音名称
"""
try:
if sound_name not in self.ambient_sounds:
return
sound_config = self.ambient_sounds[sound_name]
# 创建音频数据
audio_data = {
'name': sound_config['name'],
'file': sound_config['file'],
'config': sound_config,
'start_time': time.time(),
'volume': sound_config['volume'],
'state': 'playing',
'fade_progress': 1.0
}
# 添加到激活音频列表
self.active_audio[sound_name] = audio_data
# 更新统计信息
self.stats['sounds_played'] += 1
print(f"✓ 环境音开始播放: {sound_config['name']}")
except Exception as e:
print(f"✗ 环境音播放失败: {e}")
def _update_audio_effect_parameters(self, effect_name: str):
"""
更新音频效果参数
Args:
effect_name: 音频效果名称
"""
try:
if effect_name not in self.active_audio:
return
# 在实际实现中,这里会根据当前天气强度等因素更新音频参数
# 例如:根据风速调整风声的音量和音调
pass
except Exception as e:
print(f"✗ 音频效果参数更新失败: {e}")
def _stop_audio_effect(self, effect_name: str):
"""
停止音频效果
Args:
effect_name: 音频效果名称
"""
try:
if effect_name in self.active_audio:
audio_data = self.active_audio.pop(effect_name)
# 更新统计信息
self.stats['sounds_stopped'] += 1
print(f"✓ 音频效果已停止: {audio_data['name']}")
except Exception as e:
print(f"✗ 音频效果停止失败: {e}")
def _stop_all_audio(self):
"""停止所有音频"""
try:
audio_names = list(self.active_audio.keys())
for audio_name in audio_names:
self._stop_audio_effect(audio_name)
except Exception as e:
print(f"✗ 所有音频停止失败: {e}")
def play_sound(self, sound_name: str, volume: float = 1.0, pitch: float = 1.0):
"""
播放音频
Args:
sound_name: 音频名称
volume: 音量(0-1)
pitch: 音调(0.5-2.0)
"""
try:
# 检查是否是已知的音频效果
if sound_name in self.audio_effects or sound_name in self.ambient_sounds:
if sound_name in self.audio_effects:
self._play_audio_effect(sound_name)
else:
self._play_ambient_sound(sound_name)
else:
# 播放一次性音频
print(f"✓ 一次性音频已播放: {sound_name}")
self.stats['sounds_played'] += 1
except Exception as e:
print(f"✗ 音频播放失败: {e}")
def stop_sound(self, sound_name: str):
"""
停止音频
Args:
sound_name: 音频名称
"""
self._stop_audio_effect(sound_name)
def set_master_volume(self, volume: float):
"""
设置主音量
Args:
volume: 音量(0-1)
"""
self.audio_parameters['master_volume'] = max(0.0, min(1.0, volume))
print(f"✓ 主音量设置为: {volume}")
def set_effects_volume(self, volume: float):
"""
设置效果音量
Args:
volume: 音量(0-1)
"""
self.audio_parameters['effects_volume'] = max(0.0, min(1.0, volume))
print(f"✓ 效果音量设置为: {volume}")
def set_ambient_volume(self, volume: float):
"""
设置环境音量
Args:
volume: 音量(0-1)
"""
self.audio_parameters['ambient_volume'] = max(0.0, min(1.0, volume))
print(f"✓ 环境音量设置为: {volume}")
def get_active_audio(self) -> List[str]:
"""
获取激活的音频列表
Returns:
激活的音频名称列表
"""
return list(self.active_audio.keys())
def get_audio_info(self, audio_name: str) -> Optional[Dict[str, Any]]:
"""
获取音频信息
Args:
audio_name: 音频名称
Returns:
音频信息字典或None
"""
try:
# 检查音频效果
if audio_name in self.audio_effects:
return self.audio_effects[audio_name].copy()
# 检查环境音
if audio_name in self.ambient_sounds:
return self.ambient_sounds[audio_name].copy()
# 检查激活的音频
if audio_name in self.active_audio:
return self.active_audio[audio_name].copy()
return None
except Exception as e:
print(f"✗ 音频信息获取失败: {e}")
return None
def get_audio_effects_list(self) -> List[str]:
"""
获取所有音频效果列表
Returns:
音频效果名称列表
"""
return list(self.audio_effects.keys())
def get_ambient_sounds_list(self) -> List[str]:
"""
获取所有环境音列表
Returns:
环境音名称列表
"""
return list(self.ambient_sounds.keys())
def set_audio_parameter(self, parameter: str, value: Any):
"""
设置音频参数
Args:
parameter: 参数名称
value: 参数值
"""
try:
if parameter in self.audio_parameters:
self.audio_parameters[parameter] = value
print(f"✓ 音频参数已设置: {parameter} = {value}")
else:
print(f"✗ 无效的音频参数: {parameter}")
except Exception as e:
print(f"✗ 音频参数设置失败: {e}")
def get_audio_parameters(self) -> Dict[str, Any]:
"""
获取音频参数
Returns:
音频参数字典
"""
return self.audio_parameters.copy()
def set_transition_config(self, config: Dict[str, Any]):
"""
设置音频过渡配置
Args:
config: 配置字典
"""
self.transition_config.update(config)
print(f"✓ 音频过渡配置已更新: {self.transition_config}")
def get_transition_config(self) -> Dict[str, Any]:
"""
获取音频过渡配置
Returns:
音频过渡配置字典
"""
return self.transition_config.copy()
def get_stats(self) -> Dict[str, Any]:
"""
获取统计信息
Returns:
统计信息字典
"""
return self.stats.copy()
def reset_stats(self):
"""重置统计信息"""
self.stats = {
'sounds_played': 0,
'transitions_made': 0,
'sounds_stopped': 0,
'total_audio_time': 0.0
}
print("✓ 音频管理系统统计信息已重置")
def set_update_interval(self, interval: float):
"""
设置更新间隔
Args:
interval: 更新间隔(秒)
"""
self.update_interval = max(0.01, interval)
print(f"✓ 音频更新间隔设置为: {interval}")
def is_audio_active(self, audio_name: str) -> bool:
"""
检查音频是否激活
Args:
audio_name: 音频名称
Returns:
音频是否激活
"""
return audio_name in self.active_audio