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