650 lines
20 KiB
Python
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 |