[feature] 新增filter model设计,用于补充mvc架构

This commit is contained in:
Sam 2025-02-20 09:19:40 +08:00
parent 52d7eddf62
commit aede544740
10 changed files with 204 additions and 57 deletions

View File

@ -12,6 +12,7 @@ from Ui_widget import Ui_Widget
from checkbox_header import SCheckBoxHeaderView
# from component.widget_filter.checkbox_header import SCheckBoxHeaderView
from typing import List, Dict, Optional, Any
@ -676,69 +677,81 @@ class AudioFilterWidget(QWidget):
if __name__ == "__main__":
import sys
from PySide6.QtWidgets import QApplication
from audio_filter_model import AudioFilterModel, ChannelParams, FilterParams, FilterType
app = QApplication(sys.argv)
# Create and show widget
# widget = AudioFilterWidget()
# widget.setWindowTitle("Audio Filter Widget")
# widget.resize(800, 600)
# widget.set_channel_id(2)
# widget.set_channel("channel_2")
# test_case_3 = {
# 'delay_data2': 100.0, # 最大延迟
# 'vol_data2': -80.0, # 最小音量
# 'mix_right_data2': 100.0, # 最大混音
# 'mix_left_data2': 0.0, # 最小混音
# 'filterType2_1': 2, # 低架滤波器
# 'fc2_1': 20000.0, # 最大频率
# 'q2_1': 10.0, # 最大Q值
# 'gain2_1': 12.0, # 最大增益
# 'slope2_1': 4.0, # 最大斜率
# 'filterType2_2': 3, # 高架滤波器
# 'fc2_2': 20.0, # 最小频率
# 'q2_2': 0.1, # 最小Q值
# 'gain2_2': -12.0, # 最小增益
# 'slope2_2': 1.0 # 最小斜率
# }
# widget.set_all_params(test_case_3)
# # 获取所有参数
# params = widget.get_all_params()
# print("params:", params)
# widget.show()
# 创建模型实例
model = AudioFilterModel(channel_id=2, channel_name="channel_2")
# 设置通道参数
model.channel_params = ChannelParams(
delay=100.0,
volume=-80.0,
mix_right=100.0,
mix_left=0.0
)
# 添加滤波器
model.add_filter(FilterParams(
filter_type=FilterType.HIGHPASS,
frequency=20000.0,
q_value=10.0,
gain=12.0,
slope=4.0
))
model.add_filter(FilterParams(
filter_type=FilterType.ALLPASS,
frequency=20.0,
q_value=0.1,
gain=-12.0,
slope=1.0
))
widget_params = model.to_widget_params()
print("widget_params:", widget_params)
widget = AudioFilterWidget()
widget.setWindowTitle("Audio Filter Widget")
widget.resize(800, 600)
# 测试数据
# widget.set_filters_count(2)
# widget.set_filter_data(0, {
# 'filter_name': 'peak',
# 'filter_type': 'PEAK',
# 'freq': 100,
# 'q': 1.0,
# 'gain': 0.0,
# 'slope': 1.0,
# 'enabled': True
# })
# widget.set_filter_data(1, {
# 'filter_name': 'lowpass',
# 'filter_type': 'LOWPASS',
# 'freq': 1000,
# 'q': 0.7,
# 'gain': 0.0,
# 'slope': 2.0,
# 'enabled': True
# })
# widget.set_param_data({
# 'delay_data1': 30,
# 'ENT_volume_data1': 2,
# 'ENT_mx_right_data': 3,
# 'ENT_mix_left_data': 4
# })
widget.set_channel_id(model.channel_id)
widget.set_channel_name(model.channel_name)
widget.set_all_params(widget_params)
widget.set_channel_id(2)
widget.set_channel("channel_2")
test_case_3 = {
'delay_data2': 100.0, # 最大延迟
'vol_data2': -80.0, # 最小音量
'mix_right_data2': 100.0, # 最大混音
'mix_left_data2': 0.0, # 最小混音
'filterType2_1': 2, # 低架滤波器
'fc2_1': 20000.0, # 最大频率
'q2_1': 10.0, # 最大Q值
'gain2_1': 12.0, # 最大增益
'slope2_1': 4.0, # 最大斜率
'filterType2_2': 3, # 高架滤波器
'fc2_2': 20.0, # 最小频率
'q2_2': 0.1, # 最小Q值
'gain2_2': -12.0, # 最小增益
'slope2_2': 1.0 # 最小斜率
}
widget.set_all_params(test_case_3)
# widget.set_all_params(test_params)
# 获取所有参数
params = widget.get_all_params()
print("aaaa params:", params)
print("params:", params)
widget.show()
sys.exit(app.exec())

View File

@ -0,0 +1,134 @@
from dataclasses import dataclass, asdict
from typing import List, Dict, Any, Optional
from enum import Enum
class FilterType(Enum):
PEAK = 0
LOWPASS = 1
HIGHPASS = 2
ALLPASS = 3
@dataclass
class FilterParams:
filter_type: FilterType
frequency: float
q_value: float
gain: float
slope: float
enabled: bool = True
def to_dict(self, channel_id: int, filter_num: int) -> Dict[str, Any]:
"""转换为与组件兼容的字典格式"""
return {
f'filterType{channel_id}_{filter_num}': self.filter_type.value,
f'fc{channel_id}_{filter_num}': self.frequency,
f'q{channel_id}_{filter_num}': self.q_value,
f'gain{channel_id}_{filter_num}': self.gain,
f'slope{channel_id}_{filter_num}': self.slope
}
@classmethod
def from_dict(cls, data: Dict[str, Any], channel_id: int, filter_num: int) -> 'FilterParams':
"""从字典创建FilterParams实例"""
prefix = f'{channel_id}_{filter_num}'
return cls(
filter_type=FilterType(data.get(f'filterType{prefix}', 0)),
frequency=data.get(f'fc{prefix}', 0.0),
q_value=data.get(f'q{prefix}', 0.0),
gain=data.get(f'gain{prefix}', 0.0),
slope=data.get(f'slope{prefix}', 0.0)
)
@dataclass
class ChannelParams:
delay: float
volume: float
mix_right: float
mix_left: float
def to_dict(self, channel_id: int) -> Dict[str, Any]:
"""转换为与组件兼容的字典格式"""
return {
f'delay_data{channel_id}': self.delay,
f'vol_data{channel_id}': self.volume,
f'mix_right_data{channel_id}': self.mix_right,
f'mix_left_data{channel_id}': self.mix_left
}
@classmethod
def from_dict(cls, data: Dict[str, Any], channel_id: int) -> 'ChannelParams':
"""从字典创建ChannelParams实例"""
return cls(
delay=data.get(f'delay_data{channel_id}', 0.0),
volume=data.get(f'vol_data{channel_id}', 0.0),
mix_right=data.get(f'mix_right_data{channel_id}', 0.0),
mix_left=data.get(f'mix_left_data{channel_id}', 0.0)
)
class AudioFilterModel:
def __init__(self, channel_id: int, channel_name: str):
self.channel_id = channel_id
self.channel_name = channel_name
self.channel_params = ChannelParams(0.0, 0.0, 0.0, 0.0)
self.filters: List[FilterParams] = []
def add_filter(self, filter_params: FilterParams):
"""添加新的滤波器"""
self.filters.append(filter_params)
def remove_filter(self, index: int):
"""移除指定索引的滤波器"""
if 0 <= index < len(self.filters):
self.filters.pop(index)
def update_filter(self, index: int, filter_params: FilterParams):
"""更新指定索引的滤波器参数"""
if 0 <= index < len(self.filters):
self.filters[index] = filter_params
def to_widget_params(self) -> Dict[str, Any]:
"""转换为AudioFilterWidget兼容的参数格式"""
params = self.channel_params.to_dict(self.channel_id)
for i, filter_param in enumerate(self.filters, 1):
params.update(filter_param.to_dict(self.channel_id, i))
return params
def from_widget_params(self, params: Dict[str, Any]):
"""从AudioFilterWidget参数更新模型"""
self.channel_params = ChannelParams.from_dict(params, self.channel_id)
self.filters.clear()
filter_count = 1
while True:
if f'filterType{self.channel_id}_{filter_count}' in params:
filter_param = FilterParams.from_dict(params, self.channel_id, filter_count)
self.filters.append(filter_param)
filter_count += 1
else:
break
def save_to_file(self, filepath: str):
"""保存配置到文件"""
import json
data = {
'channel_id': self.channel_id,
'channel_name': self.channel_name,
'channel_params': asdict(self.channel_params),
'filters': [asdict(f) for f in self.filters]
}
with open(filepath, 'w') as f:
json.dump(data, f, indent=2)
@classmethod
def load_from_file(cls, filepath: str) -> 'AudioFilterModel':
"""从文件加载配置"""
import json
with open(filepath, 'r') as f:
data = json.load(f)
model = cls(data['channel_id'], data['channel_name'])
model.channel_params = ChannelParams(**data['channel_params'])
model.filters = [FilterParams(**f) for f in data['filters']]
return model