EG/plugins/user/dynamic_music_system/transitions/transition_manager.py
2025-10-30 11:46:41 +08:00

560 lines
19 KiB
Python

"""
过渡管理器
负责音乐主题之间的平滑过渡
"""
import uuid
import math
import time
import numpy as np
from typing import Dict, List, Any, Optional
class TransitionManager:
"""
过渡管理器
负责音乐主题之间的平滑过渡
"""
def __init__(self, plugin):
"""
初始化过渡管理器
Args:
plugin: 动态音乐系统插件实例
"""
self.plugin = plugin
self.transitions: Dict[str, Dict[str, Any]] = {}
self.active_transitions: Dict[str, Dict[str, Any]] = {}
self.pending_transitions: List[Dict[str, Any]] = []
self.stats = {
'transitions_registered': 0,
'transitions_active': 0,
'transitions_completed': 0,
'transitions_failed': 0,
'processing_time': 0.0
}
self.default_duration = 2.0
self.default_curve = 'linear'
# 初始化过渡管理器
self._initialize_transition_manager()
def _initialize_transition_manager(self):
"""初始化过渡管理器"""
print("✓ 过渡管理器初始化完成")
def register_transition(self, transition_name: str, transition_data: Dict[str, Any]) -> bool:
"""
注册音乐过渡
Args:
transition_name: 过渡名称
transition_data: 过渡数据
Returns:
是否注册成功
"""
try:
# 验证必需字段
required_fields = ['from_theme', 'to_theme']
for field in required_fields:
if field not in transition_data:
print(f"✗ 过渡数据缺少必需字段: {field}")
return False
# 设置默认值
transition_data.setdefault('duration', self.default_duration)
transition_data.setdefault('type', 'crossfade')
transition_data.setdefault('curve', self.default_curve)
transition_data.setdefault('interruptible', True)
transition_data.setdefault('priority', 1)
# 存储过渡数据
self.transitions[transition_name] = transition_data.copy()
self.stats['transitions_registered'] += 1
print(f"✓ 音乐过渡注册成功: {transition_name}")
return True
except Exception as e:
print(f"✗ 注册音乐过渡失败: {e}")
return False
def trigger_transition(self, transition_name: str) -> bool:
"""
触发音乐过渡
Args:
transition_name: 过渡名称
Returns:
是否触发成功
"""
try:
if transition_name not in self.transitions:
print(f"✗ 音乐过渡不存在: {transition_name}")
return False
transition_data = self.transitions[transition_name]
# 检查是否可以触发过渡
if not self._can_trigger_transition(transition_name, transition_data):
print(f"⚠ 音乐过渡无法触发: {transition_name}")
self.stats['transitions_failed'] += 1
return False
# 创建过渡实例
transition_instance = {
'name': transition_name,
'from_theme': transition_data['from_theme'],
'to_theme': transition_data['to_theme'],
'type': transition_data['type'],
'duration': transition_data['duration'],
'curve': transition_data['curve'],
'start_time': time.time(),
'elapsed_time': 0.0,
'state': 'starting'
}
# 根据过渡类型处理
if transition_data['type'] == 'crossfade':
success = self._start_crossfade(transition_instance)
elif transition_data['type'] == 'cut':
success = self._start_cut(transition_instance)
elif transition_data['type'] == 'stinger':
success = self._start_stinger(transition_instance)
else:
print(f"✗ 不支持的过渡类型: {transition_data['type']}")
self.stats['transitions_failed'] += 1
return False
if success:
# 存储活动过渡
self.active_transitions[transition_name] = transition_instance
self.stats['transitions_active'] = len(self.active_transitions)
print(f"✓ 音乐过渡已触发: {transition_name}")
return True
else:
self.stats['transitions_failed'] += 1
return False
except Exception as e:
print(f"✗ 触发音乐过渡失败: {e}")
self.stats['transitions_failed'] += 1
return False
def _can_trigger_transition(self, transition_name: str, transition_data: Dict[str, Any]) -> bool:
"""
检查是否可以触发过渡
Args:
transition_name: 过渡名称
transition_data: 过渡数据
Returns:
是否可以触发
"""
# 检查来源主题是否正在播放
from_theme = transition_data['from_theme']
if from_theme != 'any' and self.plugin.music_manager:
if not self.plugin.music_manager.is_theme_playing(from_theme):
print(f"⚠ 来源主题未在播放: {from_theme}")
return False
# 检查是否有冲突的活动过渡
for active_name, active_transition in self.active_transitions.items():
# 检查是否涉及相同的主题
if (active_transition['from_theme'] == from_theme or
active_transition['to_theme'] == from_theme or
active_transition['from_theme'] == transition_data['to_theme'] or
active_transition['to_theme'] == transition_data['to_theme']):
# 检查优先级
active_priority = self.transitions[active_name].get('priority', 1)
new_priority = transition_data.get('priority', 1)
if new_priority < active_priority:
print(f"⚠ 更高优先级的过渡正在进行: {active_name}")
return False
elif not self.transitions[active_name].get('interruptible', True):
print(f"⚠ 当前过渡不可中断: {active_name}")
return False
return True
def _start_crossfade(self, transition_instance: Dict[str, Any]) -> bool:
"""
开始交叉淡入淡出过渡
Args:
transition_instance: 过渡实例
Returns:
是否开始成功
"""
try:
from_theme = transition_instance['from_theme']
to_theme = transition_instance['to_theme']
duration = transition_instance['duration']
# 淡出来源主题
if from_theme != 'any' and self.plugin.music_manager:
self.plugin.music_manager.fade_out_theme(from_theme, duration)
# 淡入目标主题
if self.plugin.music_manager:
self.plugin.music_manager.fade_in_theme(to_theme, duration)
transition_instance['state'] = 'active'
return True
except Exception as e:
print(f"✗ 开始交叉淡入淡出过渡失败: {e}")
return False
def _start_cut(self, transition_instance: Dict[str, Any]) -> bool:
"""
开始直接切换过渡
Args:
transition_instance: 过渡实例
Returns:
是否开始成功
"""
try:
from_theme = transition_instance['from_theme']
to_theme = transition_instance['to_theme']
# 停止来源主题
if from_theme != 'any' and self.plugin.music_manager:
self.plugin.music_manager.stop_theme(from_theme)
# 播放目标主题
if self.plugin.music_manager:
self.plugin.music_manager.play_theme(to_theme, force=True)
transition_instance['state'] = 'completed'
self.stats['transitions_completed'] += 1
return True
except Exception as e:
print(f"✗ 开始直接切换过渡失败: {e}")
return False
def _start_stinger(self, transition_instance: Dict[str, Any]) -> bool:
"""
开始使用刺音过渡
Args:
transition_instance: 过渡实例
Returns:
是否开始成功
"""
try:
from_theme = transition_instance['from_theme']
to_theme = transition_instance['to_theme']
duration = transition_instance['duration']
# 淡出来源主题
if from_theme != 'any' and self.plugin.music_manager:
self.plugin.music_manager.fade_out_theme(from_theme, duration * 0.5)
# 播放刺音效果(这里简化处理)
# 在实际实现中,会播放一个短的音频文件
print("✓ 播放刺音效果")
# 淡入目标主题
if self.plugin.music_manager:
# 延迟淡入目标主题
def delayed_fade_in():
time.sleep(duration * 0.5)
self.plugin.music_manager.fade_in_theme(to_theme, duration * 0.5)
import threading
threading.Thread(target=delayed_fade_in, daemon=True).start()
transition_instance['state'] = 'active'
return True
except Exception as e:
print(f"✗ 开始刺音过渡失败: {e}")
return False
def cancel_transition(self, transition_name: str) -> bool:
"""
取消音乐过渡
Args:
transition_name: 过渡名称
Returns:
是否取消成功
"""
try:
if transition_name not in self.active_transitions:
print(f"⚠ 过渡未在进行: {transition_name}")
return True
# 取消过渡
del self.active_transitions[transition_name]
self.stats['transitions_active'] = len(self.active_transitions)
print(f"✓ 音乐过渡已取消: {transition_name}")
return True
except Exception as e:
print(f"✗ 取消音乐过渡失败: {e}")
return False
def update(self, dt: float):
"""
更新过渡管理器状态
Args:
dt: 时间增量
"""
update_start_time = time.time()
# 更新活动过渡
current_time = time.time()
completed_transitions = []
for transition_name, transition_instance in self.active_transitions.items():
if transition_instance['state'] == 'active':
elapsed_time = current_time - transition_instance['start_time']
duration = transition_instance['duration']
if elapsed_time >= duration:
# 过渡完成
transition_instance['state'] = 'completed'
completed_transitions.append(transition_name)
self.stats['transitions_completed'] += 1
# 移除已完成的过渡
for transition_name in completed_transitions:
if transition_name in self.active_transitions:
del self.active_transitions[transition_name]
self.stats['transitions_active'] = len(self.active_transitions)
# 更新性能统计
self.stats['processing_time'] += (time.time() - update_start_time)
def cleanup(self):
"""清理所有资源"""
self.transitions.clear()
self.active_transitions.clear()
self.pending_transitions.clear()
self.stats = {
'transitions_registered': 0,
'transitions_active': 0,
'transitions_completed': 0,
'transitions_failed': 0,
'processing_time': 0.0
}
print("✓ 过渡管理器资源已清理")
def get_stats(self) -> Dict[str, int]:
"""
获取统计信息
Returns:
统计信息字典
"""
return self.stats.copy()
def get_active_transitions(self) -> List[str]:
"""
获取活动过渡列表
Returns:
活动过渡名称列表
"""
return list(self.active_transitions.keys())
def get_transition_status(self, transition_name: str) -> Dict[str, Any]:
"""
获取过渡状态
Args:
transition_name: 过渡名称
Returns:
过渡状态字典
"""
if transition_name in self.active_transitions:
transition_instance = self.active_transitions[transition_name]
return {
'name': transition_name,
'state': transition_instance['state'],
'from_theme': transition_instance['from_theme'],
'to_theme': transition_instance['to_theme'],
'elapsed_time': transition_instance['elapsed_time'],
'duration': transition_instance['duration']
}
elif transition_name in self.transitions:
return {
'name': transition_name,
'state': 'registered',
'from_theme': self.transitions[transition_name]['from_theme'],
'to_theme': self.transitions[transition_name]['to_theme']
}
else:
return {
'name': transition_name,
'state': 'unknown'
}
def set_default_duration(self, duration: float):
"""
设置默认过渡持续时间
Args:
duration: 持续时间(秒)
"""
self.default_duration = max(0.1, duration)
print(f"✓ 默认过渡持续时间设置为: {self.default_duration:.2f}")
def set_default_curve(self, curve: str):
"""
设置默认过渡曲线
Args:
curve: 曲线类型 (linear, exponential, logarithmic, ease_in, ease_out, ease_in_out)
"""
valid_curves = ['linear', 'exponential', 'logarithmic', 'ease_in', 'ease_out', 'ease_in_out']
if curve not in valid_curves:
print(f"✗ 无效的曲线类型: {curve}")
return
self.default_curve = curve
print(f"✓ 默认过渡曲线设置为: {self.default_curve}")
def create_dynamic_transition(self, from_theme: str, to_theme: str,
transition_type: str = 'crossfade', duration: float = None) -> str:
"""
创建动态过渡
Args:
from_theme: 来源主题
to_theme: 目标主题
transition_type: 过渡类型
duration: 持续时间(秒)
Returns:
过渡名称
"""
try:
# 生成唯一过渡名称
transition_name = f"dynamic_{from_theme}_to_{to_theme}_{int(time.time())}"
# 创建过渡数据
transition_data = {
'from_theme': from_theme,
'to_theme': to_theme,
'type': transition_type,
'duration': duration if duration is not None else self.default_duration
}
# 注册过渡
if self.register_transition(transition_name, transition_data):
return transition_name
else:
return ""
except Exception as e:
print(f"✗ 创建动态过渡失败: {e}")
return ""
def is_transition_active(self, transition_name: str) -> bool:
"""
检查过渡是否正在进行
Args:
transition_name: 过渡名称
Returns:
是否正在进行
"""
return transition_name in self.active_transitions
def get_transition_progress(self, transition_name: str) -> float:
"""
获取过渡进度
Args:
transition_name: 过渡名称
Returns:
过渡进度 (0.0-1.0)
"""
if transition_name in self.active_transitions:
transition_instance = self.active_transitions[transition_name]
elapsed_time = time.time() - transition_instance['start_time']
duration = transition_instance['duration']
return min(1.0, elapsed_time / duration)
return 0.0
def pause_transition(self, transition_name: str) -> bool:
"""
暂停过渡
Args:
transition_name: 过渡名称
Returns:
是否暂停成功
"""
try:
if transition_name not in self.active_transitions:
print(f"⚠ 过渡未在进行: {transition_name}")
return False
transition_instance = self.active_transitions[transition_name]
transition_instance['state'] = 'paused'
transition_instance['pause_time'] = time.time()
print(f"✓ 过渡已暂停: {transition_name}")
return True
except Exception as e:
print(f"✗ 暂停过渡失败: {e}")
return False
def resume_transition(self, transition_name: str) -> bool:
"""
恢复过渡
Args:
transition_name: 过渡名称
Returns:
是否恢复成功
"""
try:
if transition_name not in self.active_transitions:
print(f"⚠ 过渡未在进行: {transition_name}")
return False
transition_instance = self.active_transitions[transition_name]
if transition_instance['state'] == 'paused':
# 计算暂停时间并调整开始时间
pause_duration = time.time() - transition_instance.get('pause_time', time.time())
transition_instance['start_time'] += pause_duration
transition_instance['state'] = 'active'
print(f"✓ 过渡已恢复: {transition_name}")
return True
else:
print(f"⚠ 过渡未暂停: {transition_name}")
return False
except Exception as e:
print(f"✗ 恢复过渡失败: {e}")
return False