From 8619d64f3cf0cf4a7bc81839ba2a626e330b307a Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 26 Feb 2025 01:30:51 +0800 Subject: [PATCH] =?UTF-8?q?[feature]=20=E6=96=B0=E5=A2=9E=E6=BB=A4?= =?UTF-8?q?=E6=B3=A2=E5=99=A8=E6=95=B0=E6=8D=AE=E4=BB=8E.csv=E4=B8=AD?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 254 ++++++++++++++---- .../__pycache__/__init__.cpython-313.pyc | Bin 135 -> 157 bytes .../application_controller.cpython-313.pyc | Bin 3903 -> 3925 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 261 -> 283 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 286 -> 308 bytes .../ui_widget_card.cpython-313.pyc | Bin 10478 -> 10500 bytes .../__pycache__/widget_card.cpython-313.pyc | Bin 34452 -> 36385 bytes component/widget_card/widget_card.py | 54 +++- .../__pycache__/__init__.cpython-313.pyc | Bin 148 -> 170 bytes .../ui_widget_channel.cpython-313.pyc | Bin 109032 -> 109054 bytes .../widget_channel.cpython-313.pyc | Bin 6555 -> 6577 bytes .../__pycache__/Ui_widget.cpython-313.pyc | Bin 77757 -> 77779 bytes .../Ui_widget_origin.cpython-313.pyc | Bin 76763 -> 76785 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 147 -> 169 bytes .../audio_filter_componet.cpython-313.pyc | Bin 59394 -> 59280 bytes .../audio_filter_controller.cpython-313.pyc | Bin 25970 -> 28649 bytes .../audio_filter_model.cpython-313.pyc | Bin 12670 -> 12692 bytes .../checkbox_header.cpython-313.pyc | Bin 3345 -> 3367 bytes .../__pycache__/resources.cpython-313.pyc | Bin 2074 -> 2096 bytes .../widget_filter/audio_filter_componet.py | 2 +- .../widget_filter/audio_filter_controller.py | 90 ++++++- .../__pycache__/log_handler.cpython-313.pyc | Bin 2415 -> 2437 bytes .../__pycache__/ui_widget_log.cpython-313.pyc | Bin 4190 -> 4212 bytes .../__pycache__/widget_log.cpython-313.pyc | Bin 5835 -> 5857 bytes .../__pycache__/Ui_widget.cpython-313.pyc | Bin 61890 -> 61912 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 145 -> 167 bytes .../__pycache__/widget_main.cpython-313.pyc | Bin 1184 -> 1206 bytes data/projects/default.json | 118 -------- .../{test_project_param2.csv => aaa_abc.csv} | 49 ++-- .../{test_project_param1.csv => aaa_abcd.csv} | 0 data/projects/test_project.json | 36 +-- .../__pycache__/data_store.cpython-313.pyc | Bin 18907 -> 19043 bytes .../data_store_manager.cpython-313.pyc | Bin 3803 -> 8281 bytes persistence/data_store.py | 21 +- persistence/data_store_manager.py | 33 +++ 35 files changed, 420 insertions(+), 237 deletions(-) delete mode 100644 data/projects/default.json rename data/projects/params/{test_project_param2.csv => aaa_abc.csv} (95%) rename data/projects/params/{test_project_param1.csv => aaa_abcd.csv} (100%) diff --git a/app.py b/app.py index b8122f3..84e52d4 100644 --- a/app.py +++ b/app.py @@ -11,7 +11,7 @@ from component.widget_filter.audio_filter_model import AudioFilterModel from component.widget_filter.audio_filter_controller import AudioFilterController from component.widget_card.widget_card import ParamData from component.widget_log.widget_log import Widget_Log -from persistence.data_store_manager_origin import DataStoreManager +from persistence.data_store_manager import DataStoreManager from persistence.data_store_origin import DataStore from param_struct_test.service_manager import ServiceManager from application.application_controller import ApplicationController @@ -97,7 +97,7 @@ class MainWindow(QWidget): if param_info.get('name') == selected_name: return True return False - # app.py + def update_channel_from_card(self): """根据选中的卡片更新通道数据""" try: @@ -105,80 +105,98 @@ class MainWindow(QWidget): selected_param_name, selected_project_name = self.widget_card.get_selected_param_name() logger.info(f"selected_param_name: {selected_param_name}, selected_project_name: {selected_project_name}") - # 2. 获取项目数据 - projects = self.data_manager.get_projects() - project_name = projects[0] - project_data = self.data_manager.get_project(project_name) - - if not project_data or 'params' not in project_data: - logger.error("Project data not found or invalid") + if not selected_param_name or not selected_project_name: + logger.warning("未选择参数或项目") return - - # 3. 查找匹配的参数数据 - param_data = None - for key, param_info in project_data['params'].items(): - if param_info.get('name') == selected_param_name: - param_data = param_info - break - - if not param_data or 'channels' not in param_data: - logger.error(f"Parameter data not found for name: {selected_param_name}") + + # 2. 获取参数数据 + param_data = self.data_manager.get_param_data(selected_project_name, selected_param_name) + + # 新增: 根据参数名称查找对应的参数键并更新current_param + # project_names = self.data_manager.get_projects() + # project_data = self.data_manager.get_project(project_names[0]) + # if project_data and 'params' in project_data: + # for param_key, param_info in project_data['params'].items(): + # if param_info.get('name') == selected_param_name: + # # 找到匹配的参数键,更新current_param + # self.data_manager.current_param = param_key + # logger.info(f"已更新当前参数键: {param_key}") + # break + + self.data_manager.current_param = param_data + if not param_data: + logger.error(f"未找到参数数据: {selected_param_name}") return - - # 4. 处理每个通道的数据 - for channel_id, channel_data in param_data['channels'].items(): + + # 3. 处理每个通道的数据 + for channel_id, channel_data in param_data.items(): try: - channel_id = int(channel_id) - 1 # JSON中通道从1开始,程序中从0开始 + channel_id = int(channel_id) if 0 <= channel_id < len(self.filter_controllers): controller = self.filter_controllers[channel_id] controller.update_from_card_data(channel_data) - # controller.update_ui() except Exception as e: - logger.error(f"Error processing channel {channel_id}: {str(e)}") + logger.error(f"处理通道 {channel_id} 时出错: {str(e)}") continue - logger.info("Successfully updated all channels from card data") + logger.info("成功从卡片数据更新所有通道") except Exception as e: - logger.error(f"Error updating channel from card: {str(e)}") + logger.error(f"从卡片更新通道时出错: {str(e)}") def load_default_project(self): """Load the first available project or create a default one if none exists""" try: + # 获取项目列表 projects = self.data_manager.get_projects() if not projects: - # Create default project if none exists - logger.info("Creating default project...") - self.data_manager.create_project("default", "Default project configuration") + # 如果没有项目,创建默认项目 + logger.info("创建默认项目...") + self.data_manager.create_project("default", "默认项目配置") projects = ["default"] - # Load the first project - project_name = projects[0] - project_data = self.data_manager.get_project(project_name) - - logger.info(f"Loading project: {project_name}") - - if project_data and 'params' in project_data: - self.widget_card.list_widget.clear() - - # 将字符串转换为 ParamData 对象 - param_objects = [ - ParamData(name=param_data['name']) - for param_data in project_data['params'].values() - ] - - card_data = CardData( - name=project_data['name'], - date=project_data['created_at'].split('T')[0], - description=project_data['description'], - params=param_objects # 使用 ParamData 对象列表 - ) + # 清空当前卡片列表 + self.widget_card.list_widget.clear() - self.widget_card.add_card_item(card_data) + # 遍历所有项目并加载 + for project_name in projects: + # 从数据管理器获取项目数据 + project_data = self.data_manager.get_project(project_name) + #to do:目前支持一个项目 + self.data_manager._store.current_project = project_name + if not project_data: + logger.warning(f"无法加载项目: {project_name}") + continue + + logger.info(f"加载项目: {project_name}") + + # 检查项目数据是否包含参数 + if 'params' in project_data: + # 创建参数对象列表 + param_objects = [] + for param_id, param_data in project_data['params'].items(): + if isinstance(param_data, dict) and 'name' in param_data: + param_objects.append(ParamData(name=param_data['name'])) + + # 创建卡片数据 + card_data = CardData( + name=project_data.get('name', project_name), + date=project_data.get('created_at', '').split('T')[0] if 'created_at' in project_data else '', + description=project_data.get('description', ''), + params=param_objects + ) + + # 添加卡片到界面 + self.widget_card.add_card_item(card_data) + logger.info(f"已添加项目卡片 '{project_data.get('name', project_name)}' 包含 {len(param_objects)} 个参数") + else: + logger.warning(f"项目 '{project_name}' 没有参数数据") except Exception as e: - logger.error(f"Error loading default project: {e}") + logger.error(f"加载默认项目时出错: {str(e)}") + import traceback + logger.error(traceback.format_exc()) def load_config(self): """加载通道配置文件""" @@ -219,9 +237,83 @@ class MainWindow(QWidget): print("setup_connections") self.widget_channel.channel_btn_clicked.connect(self.on_channel_btn_clicked) self.widget_card.parameterSelected.connect(self.on_widget_card_parameter_selected) - + # 连接编辑信号 + self.widget_card.itemEdited.connect(self.on_widget_card_item_edited) + # 连接参数添加信号 + self.widget_card.parameterAdded.connect(self.on_widget_card_parameter_added) + + # data_store_manager.current_param def on_widget_card_parameter_selected(self, param_name: str, project_name: str): logger.info(f"on_widget_card_parameter_selected: {param_name}, {project_name}") + + try: + # 获取参数数据 + param_data = self.data_manager.get_param_data(project_name, param_name) + + if not param_data: + logger.warning(f"未找到参数数据: {param_name}") + return + + # 更新所有通道的滤波器数据 + for channel_id, channel_data in param_data.items(): + try: + channel_id = int(channel_id) + if 0 <= channel_id < len(self.filter_controllers): + controller = self.filter_controllers[channel_id] + controller.update_from_card_data(channel_data) + except Exception as e: + logger.error(f"处理通道 {channel_id} 时出错: {str(e)}") + continue + + logger.info(f"成功从参数 {param_name} 更新所有通道") + except Exception as e: + logger.error(f"参数选择更新出错: {str(e)}") + import traceback + logger.error(traceback.format_exc()) + + def on_widget_card_item_edited(self, edit_type, old_value, new_value, project_name): + """处理卡片项目编辑事件""" + if edit_type == "parameter_name": + try: + # 查找项目文件名 + projects = self.data_manager.get_projects() + project_filename = None + + for proj_filename in projects: + project_data = self.data_manager.get_project(proj_filename) + if project_data and project_data.get('name') == project_name: + project_filename = proj_filename + + # 1. 更新JSON中的参数名 + if 'params' in project_data: + for param_id, param_info in project_data['params'].items(): + if param_info.get('name') == old_value: + # 更新参数名 + param_info['name'] = new_value + # 保存更新后的项目数据 + self.data_manager.update_project(proj_filename, project_data) + logger.info(f"已更新参数名: {old_value} -> {new_value}") + + # 2. 重命名参数文件 + params_dir = os.path.join("data", "projects", "params") + for file in os.listdir(params_dir): + # 查找与旧参数名匹配的文件 + if file.startswith(f"{project_name}_") and file.endswith('.csv'): + param_part = file[len(project_name)+1:-4] # 提取参数名部分 + if param_part == old_value: + old_path = os.path.join(params_dir, file) + new_path = os.path.join(params_dir, f"{project_name}_{new_value}.csv") + try: + os.rename(old_path, new_path) + logger.info(f"已重命名参数文件: {old_path} -> {new_path}") + except Exception as e: + logger.error(f"重命名参数文件失败: {str(e)}") + break + break + except Exception as e: + logger.error(f"处理参数编辑时出错: {str(e)}") + import traceback + logger.error(traceback.format_exc()) def set_default_filter_widget(self, channel_id: int): while self.widget_main.ui.verticalLayout_Filter.count(): @@ -242,6 +334,7 @@ class MainWindow(QWidget): # Add the selected channel's filter widget to the layout filter_widget = self.widget_filter_list[channel_id] self.widget_main.ui.verticalLayout_Filter.addWidget(filter_widget) + filter_widget.ui.groupBox_4.setTitle(f"Channel {channel_id+1}") filter_widget.show() def test_communication(self): @@ -352,6 +445,59 @@ class MainWindow(QWidget): return channel_data + def on_widget_card_parameter_added(self, param_name: str, project_name: str): + """处理添加新参数的事件""" + logger.info(f"添加新参数: {param_name}, 项目: {project_name}") + + try: + # 获取项目列表 + projects = self.data_manager.get_projects() + project_found = False + project_filename = None + + # 查找对应的项目文件名 + for proj_filename in projects: + project_data = self.data_manager.get_project(proj_filename) + if project_data and project_data.get('name') == project_name: + project_found = True + project_filename = proj_filename + + # 创建空的通道数据结构 + empty_channel_data = {} + for i in range(len(self.filter_controllers)): + empty_channel_data[i] = { + 'delay_data': 0.0, + 'vol_data': 0.0, + 'mix_left_data': 0.0, + 'mix_right_data': 0.0, + 'filters': [] + } + + # 保存新参数 - 使用项目文件名 + self.data_manager.save_param(project_filename, param_name, empty_channel_data, "") + + # 重命名参数文件,使用项目的name字段而不是文件名 + old_param_path = os.path.join("data", "projects", "params", f"{project_filename}_{param_name}.csv") + new_param_path = os.path.join("data", "projects", "params", f"{project_name}_{param_name}.csv") + + if os.path.exists(old_param_path): + try: + os.rename(old_param_path, new_param_path) + logger.info(f"已重命名参数文件: {old_param_path} -> {new_param_path}") + except Exception as e: + logger.error(f"重命名参数文件失败: {str(e)}") + + logger.info(f"已创建新参数: {param_name}, 文件名: {project_name}_{param_name}.csv") + break + + if not project_found: + logger.warning(f"未找到项目: {project_name}") + + except Exception as e: + logger.error(f"创建参数时出错: {str(e)}") + import traceback + logger.error(traceback.format_exc()) + if __name__ == '__main__': import sys from PySide6.QtWidgets import QApplication diff --git a/application/__pycache__/__init__.cpython-313.pyc b/application/__pycache__/__init__.cpython-313.pyc index 7d14cf3348aaa0715b46fc293ea6fc6b052eea63..cce8e1e0b6bb893aa329c6ca417ab7bbe3f22040 100644 GIT binary patch delta 60 zcmZo?oXg1lnU|M~0SG3{+clBfSk=bGD#o!au{b`svbZEQHzu(tIU}w)(s~E?!#Nzni%HopL+?d3o)VHQyU delta 38 scmdnOG>?hD3nU|M~0SHpB?%l|}nMu{h#VW?JEU`E~xU#q;H8&=)C^;juBsICDv?x`# RpeQl9Br`d6^I0ZEH2}mL7Wx1H delta 41 vcmZn(dKbw3nU|M~0SL|?+`W-|GZVj=hgFPYSz>W~aAk2xYVPL8Op0m%C*KZb diff --git a/component/widget_card/__pycache__/widget_card.cpython-313.pyc b/component/widget_card/__pycache__/widget_card.cpython-313.pyc index e34ccf4043e9dbc702adfdfcebe631c79566925e..37edbc6380723234c739cca94bd87fd495001135 100644 GIT binary patch delta 5386 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 BQyTyP delta 3927 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 diff --git a/component/widget_card/widget_card.py b/component/widget_card/widget_card.py index 549c11d..58db273 100644 --- a/component/widget_card/widget_card.py +++ b/component/widget_card/widget_card.py @@ -34,6 +34,8 @@ class CardData: class Widget_Card(QWidget): parameterSelected = Signal(str, str) # Signal that emits (parameter_name, project_name) + itemEdited = Signal(str, str, str, str) # Signal that emits (edit_type, old_value, new_value, project_name) + parameterAdded = Signal(str, str) # Signal that emits (parameter_name, project_name) def __init__(self): super().__init__() @@ -44,6 +46,11 @@ class Widget_Card(QWidget): self.list_widget.itemDelegate().parameterSelected.connect( lambda param_name, project_name: self.parameterSelected.emit(param_name, project_name) ) + + # Connect the itemDelegate's itemEdited signal + self.list_widget.itemDelegate().itemEdited.connect( + lambda edit_type, old_value, new_value, project_name: self.itemEdited.emit(edit_type, old_value, new_value, project_name) + ) def setup_ui(self): self.setWindowTitle("卡片列表示例") @@ -280,6 +287,9 @@ class Widget_Card(QWidget): item_height = self.calculate_item_height(data) item.setSizeHint(QSize(380, item_height)) + # 发射参数添加信号 + self.parameterAdded.emit(new_param.name, data.name) + # 刷新显示 self.list_widget.viewport().update() @@ -320,8 +330,24 @@ class Widget_Card(QWidget): return None, None + def add_parameter(self, param_name: str): + """添加新参数到当前选中的项目""" + current_item = self.list_widget.currentItem() + if current_item: + card_data = current_item.data(Qt.ItemDataRole.UserRole) + card_data.params.append(ParamData(name=param_name)) + + # 更新UI + self.list_widget.viewport().update() + + # 发射参数添加信号 + self.parameterAdded.emit(param_name, card_data.name) + return True + return False + class CardItemDelegate(QStyledItemDelegate): parameterSelected = Signal(str, str) # Signal that emits (parameter_name, project_name) + itemEdited = Signal(str, str, str, str) # Signal that emits (edit_type, old_value, new_value, project_name) def __init__(self, parent=None): super().__init__(parent) @@ -343,12 +369,13 @@ class CardItemDelegate(QStyledItemDelegate): desc_rect = self.getDescriptionRect(option.rect) if event.type() == QEvent.MouseButtonDblClick: - if title_rect.contains(pos): - self.editing_field = 'name' - self.edit_rect = title_rect - self.parent().edit(index) - return True - elif desc_rect.contains(pos): + # 移除对标题区域双击事件的处理 + # if title_rect.contains(pos): + # self.editing_field = 'name' + # self.edit_rect = title_rect + # self.parent().edit(index) + # return True + if desc_rect.contains(pos): self.editing_field = 'description' self.edit_rect = desc_rect self.parent().edit(index) @@ -444,14 +471,29 @@ class CardItemDelegate(QStyledItemDelegate): return data = index.data(Qt.ItemDataRole.UserRole) + old_value = "" + edit_type = "" + if self.editing_field == 'name': + old_value = data.name data.name = editor.text() + edit_type = "project_name" elif self.editing_field == 'description': + old_value = data.description data.description = editor.text() + edit_type = "project_description" elif self.editing_param_index >= 0: + old_value = data.params[self.editing_param_index].name data.params[self.editing_param_index].name = editor.text() + edit_type = "parameter_name" model.setData(index, data, Qt.ItemDataRole.UserRole) + + # 发射编辑完成信号 + if old_value != editor.text(): + print(f"发射编辑完成信号: {edit_type}, {old_value}, {editor.text()}, {data.name}") + self.itemEdited.emit(edit_type, old_value, editor.text(), data.name) + self.editing_field = None self.editing_param_index = -1 diff --git a/component/widget_channel/__pycache__/__init__.cpython-313.pyc b/component/widget_channel/__pycache__/__init__.cpython-313.pyc index 5afb7158ad691437f3b85283aa39f49333c07b30..01974309d5b7bfb2cd41f9a4e25aa7ebaff16fac 100644 GIT binary patch delta 60 zcmbQjxQdbcGcPX}0}wnsymcbCv8tzwRg7aGcPX}0}yCD-8_-onBUmLD#o!au{b`svbZEQcVeW~aAk2xYHmzoQF2CRNosOQ WX;G?fK~Z9INoI2Dc4c?Qqe%cFpcpIw delta 46 zcmex&neD}8Hm=XSyj%=G@OV=r*H$h@E_Z$#533l*vc%%};L75X)ZFcs?u7Ou~{yj%=GpntrPYbzJyR9;n27poY@vc%%};L75X)ZCcFqU4OslGNmq W(xOz|f}+IalFa1P?dy0M`IP`3(-(~Z delta 46 zcmcb7pJnfT7Ou~{yj%=GaBo#3*H$jZsl5Eg9#%1qWr@Y{!Ii}&skz&a@G|l%0RVGm B4>kY* diff --git a/component/widget_filter/__pycache__/Ui_widget_origin.cpython-313.pyc b/component/widget_filter/__pycache__/Ui_widget_origin.cpython-313.pyc index 9d5cf9ad41e0218df6c321a69b5aebd1b1537020..9e7e582a8269b63dc26b7873d274eb2a8460e7d2 100644 GIT binary patch delta 69 zcmcb8o#o?o7Vgiyyj%=GpnrUCBllKrMoDhf02iwm$FjuY_~6RolGNOo#G>Sk%#zgP XlG377-GZXT6 delta 47 zcmex(o#pm*7Vgiyyj%=G@WF0NBllKrMoDgdD-Wv}$FjuY_~6RolGNPop4^Np6aas5 B4`KiS diff --git a/component/widget_filter/__pycache__/__init__.cpython-313.pyc b/component/widget_filter/__pycache__/__init__.cpython-313.pyc index a3637de9ae95e832af9b3feecaf7b91bd2d1b862..e4f88846ad71628aeba09af8ed9e8ad0cddaba74 100644 GIT binary patch delta 60 zcmbQtxRR0kGcPX}0}wnsymcbCv8soQRg7ab8c=LB}dca2BFgDdt7poY@vc%%};L75X)ZCcFqU4OslGNmq z(xOz|f}+IalFa1P%|&b*8klbJPkvZ0HF-h1=;Zzz(v$Prc^Rinu4zwajGw%*Qg^cd z8Ij4|9a)n%)d^27DCC$d(8%31P0mV!vCW`j+>CL&LZq#WRpFnh%zcpJ}4qJ zxnfE>QXF#f%Q7%TBjQm2IUac;&Zz?<*EbocM0xVZM!CreQ$-n7Cznmtoh-Z&9K9@g zg3OhLcxJQ)V=p%%~&j`oOW-Y1RQ>0B&(0TL1t6 delta 861 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 delta 4705 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 RK~Z9INoI2DW;f>3oB)<^7B>I@ delta 41 vcmZ23HBpNDGcPX}0}z~O*s_sZhne5f!z#wHEU`E~xU#q;HFt9i^Jz{1`A`h; diff --git a/component/widget_filter/__pycache__/resources.cpython-313.pyc b/component/widget_filter/__pycache__/resources.cpython-313.pyc index 835b1ae4fa7c5338080521d335e27c07911cd62c..760073ee4b6aa3b01393283af466f50acdc622fd 100644 GIT binary patch delta 63 zcmbOwut9+PGcPX}0}wnsymceDI-9Dei&czcSz>W~aAk2xYHmzoQF2CRNosOQX;G?f RK~Z9INoI2DW=FQ0i~y9l7BK(- delta 41 vcmdlWFiU{@GcPX}0}$*m+p>{cosHkv!z#wHEU`E~xU#q;HFtA3+f7CQ?&b`U diff --git a/component/widget_filter/audio_filter_componet.py b/component/widget_filter/audio_filter_componet.py index a1e208e..6789665 100644 --- a/component/widget_filter/audio_filter_componet.py +++ b/component/widget_filter/audio_filter_componet.py @@ -706,7 +706,7 @@ class AudioFilterWidget(QWidget): self.current_filter_index = row filter_name_item = self.ui.tableWidget.item(row, 1) if filter_name_item: - self.ui.groupBox_4.setTitle(filter_name_item.text()) + # self.ui.groupBox_4.setTitle(filter_name_item.text()) # 获取当前滤波器类型和slope值 filter_type_combo = self.ui.tableWidget.cellWidget(row, 2) diff --git a/component/widget_filter/audio_filter_controller.py b/component/widget_filter/audio_filter_controller.py index 472d3e7..7994708 100644 --- a/component/widget_filter/audio_filter_controller.py +++ b/component/widget_filter/audio_filter_controller.py @@ -17,6 +17,7 @@ from component.widget_filter.audio_filter_model import AudioFilterModel from component.widget_filter.audio_filter_componet import AudioFilterWidget from component.widget_filter.audio_filter_model import FilterParams, FilterType, ChannelParams from param_struct_test.params_service import Response, CMD +from persistence.data_store_manager import DataStoreManager # from audio_filter_model import AudioFilterModel # from audio_filter_componet import AudioFilterWidget @@ -90,7 +91,6 @@ class AudioFilterController(QObject): try: self.state = AudioControllerState.UPDATING - # 1. Update channel parameters channel_params = ChannelParams( delay=card_data.get('delay_data', 0.0), volume=card_data.get('vol_data', 0.0), @@ -99,22 +99,47 @@ class AudioFilterController(QObject): ) self.model.set_channel_params(channel_params) - # 2. Clear existing filters and add new ones self.model.filters.clear() - # Convert and add new filters for filter_data in card_data.get('filters', []): - filter_type = FilterType[filter_data['type']] + # 检查滤波器参数是否都为0 + all_zeros = all([ + filter_data.get('frequency', 0.0) == 0.0 and filter_data.get('fc', 0.0) == 0.0, + filter_data.get('q', 0.0) == 0.0, + filter_data.get('gain', 0.0) == 0.0, + filter_data.get('slope', 0.0) == 0.0 + ]) + + # 如果所有参数都为0,跳过这个滤波器 + if all_zeros: + continue + + # 正确处理整数类型的 filterType + filter_type = None + if 'type' in filter_data and filter_data['type'] is not None: + # 如果是字符串名称 + if isinstance(filter_data['type'], str): + filter_type = FilterType[filter_data['type']] + # 如果是整数值 + elif isinstance(filter_data['type'], int): + filter_type = FilterType(filter_data['type']) + elif 'filterType' in filter_data and filter_data['filterType'] is not None: + # 如果是字符串名称 + if isinstance(filter_data['filterType'], str): + filter_type = FilterType[filter_data['filterType']] + # 如果是整数值 + elif isinstance(filter_data['filterType'], int): + filter_type = FilterType(filter_data['filterType']) + filter_params = FilterParams( filter_type=filter_type, - frequency=filter_data['frequency'], - q_value=filter_data['q'], - gain=filter_data['gain'], - slope=filter_data['slope'] + frequency=filter_data.get('frequency', 0.0) or filter_data.get('fc', 0.0), + q_value=filter_data.get('q', 0.0), + gain=filter_data.get('gain', 0.0), + slope=filter_data.get('slope', 0.0) ) self.model.filters.append(filter_params) - # 3. Update UI if self.widget: self.widget.updateUI() @@ -442,9 +467,56 @@ class AudioFilterController(QObject): self.model.update_filter(index, filter_params) print(f"_on_widget_filter_changed model:{self.model.filters}") # self.filter_changed.emit(index, param_name, value) + + # 同步更新CSV文件中的数据 + self._sync_to_csv() except Exception as e: self.error_occurred.emit(f"Error updating filter: {str(e)}") + def _sync_to_csv(self): + """同步当前滤波器数据到CSV文件""" + try: + # 获取当前项目和参数名称 + data_store_manager = DataStoreManager.get_instance() + current_project = data_store_manager.current_project + current_param = data_store_manager.current_param + + + # 如果仍然没有当前项目或参数,则不进行同步 + if not current_project or not current_param: + return + + # 准备通道数据 + channel_data = {} + model_data = self.model.get_all_data() + channel_id = model_data['channel_id'] + + # 构建通道数据结构 + channel_data[channel_id] = { + 'mix_left_data': model_data['channel_params']['mix_left'], + 'mix_right_data': model_data['channel_params']['mix_right'], + 'delay_data': model_data['channel_params']['delay'], + 'vol_data': model_data['channel_params']['volume'], + 'filters': [] + } + + # 添加滤波器数据 + for filter_param in model_data['filters']: + filter_data = { + 'fc': filter_param['frequency'], + 'q': filter_param['q_value'], + 'gain': filter_param['gain'], + 'slope': filter_param['slope'], + 'filterType': filter_param['filter_type'].value + } + channel_data[channel_id]['filters'].append(filter_data) + + # 保存到CSV文件 + data_store_manager.save_param(current_project, current_param, channel_data) + + except Exception as e: + self.error_occurred.emit(f"同步到CSV文件时发生错误: {str(e)}") + # def _on_widget_param_changed(self, param_name: str, value: float): # """处理widget通道参数变化""" # try: diff --git a/component/widget_log/__pycache__/log_handler.cpython-313.pyc b/component/widget_log/__pycache__/log_handler.cpython-313.pyc index 4242896023653d842a1c3daddaefcad6da6ab5f8..f87d8e4d18941c31e5f251ca6eb98bcfc2db5434 100644 GIT binary patch delta 63 zcmaDa)GEyVnU|M~0SLCf-L;W>C!?x|i&czcSz>W~aAk2xYHmzoQF2CRNosOQX;G?f RK~Z9INoI2D=F5z8*a5p=7exR7 delta 41 vcmZn_elNuRnU|M~0SL|?+`W-|CnLX+hgFPYSz>W~aAk2xYVPKjjC0rl77Y$d diff --git a/component/widget_log/__pycache__/ui_widget_log.cpython-313.pyc b/component/widget_log/__pycache__/ui_widget_log.cpython-313.pyc index 2bde4ef5c4e68e2a1f484cd4c00ecdd7c4fed0ad..259fa81b2ab35989e263e73dd38f3b4f2dc7e81c 100644 GIT binary patch delta 63 zcmcbo@I`_9GcPX}0}$+dxoac0DTk_;i&czcSz>W~aAk2xYHmzoQF2CRNosOQX;G?f RK~Z9INoI2DW`7QT4gkMb7CHa` delta 41 vcmeyOa8H5zGcPX}0}z})xO*eFDF?rahgFPYSz>W~aAk2xYVPJ#4t@>*8!HV! diff --git a/component/widget_log/__pycache__/widget_log.cpython-313.pyc b/component/widget_log/__pycache__/widget_log.cpython-313.pyc index 7a43192ef7506d72eba5c13f81c08e314e8cbf83..9bff25755a4633748e92e9ca1d5e0ec9c2a34901 100644 GIT binary patch delta 63 zcmX@D`%strGcPX}0}$+dziT7+88%gS7poY@vc%%};L75X)ZCcFqU4OslGNmq(xOz| Sf}+IalFa1P&Cl4L@&f?dIT$zq delta 41 wcmaE;ds>(KGcPX}0}z})xO*e_88&`H533l*vc%%};L75X)ZEQ~*q-tO04ie-H~;_u diff --git a/component/widget_main/__pycache__/Ui_widget.cpython-313.pyc b/component/widget_main/__pycache__/Ui_widget.cpython-313.pyc index 61e8ef32b9032ba00c14fb8a64c2ace177eb6363..7fe80db50968ec345c8f866627d970f94bbaea02 100644 GIT binary patch delta 64 zcmX@~nEA$IX0Fe?yj%=GpnrTLm;EzUcNeP|$FjuY_~6RolGNOo#G>Sk%#zgPlG377 S-GZXT-v9sr diff --git a/component/widget_main/__pycache__/widget_main.cpython-313.pyc b/component/widget_main/__pycache__/widget_main.cpython-313.pyc index 067eb7c58557cf3f544366dbf88771cc69681bd0..75f30b196f466a4d08cbfa2ccf92f19a8b310317 100644 GIT binary patch delta 62 zcmZ3$xs8+SGcPX}0}$vR-^dlrr0VHn72{ZzSR5Z*SzMBu8tBH%5rlo>7m*zmJ1g~7674&l<6j3)J ze1>&8w&z$BK|5jJ$}Tm^$(zkiIh$3B;F==Y8Jqd%pMY6Txp|sNK|P zlt9h=`_;h9rsvvc4(0-q_L^ey)Z0M#f?ipK3vuLL!D)>=Y>Lle5}O%5-y>#-oq}bto0@AQVCb@5#JTAF!)1!Tx>*g!<(U;k^wvb0U`|P<;{vg zfCw98$gv~?RLnx2$Q@=j9aZpSdW?RMcMGV8WsJ9+CaK0t5fv(Zlk-h~~K zUeTVeqCT*SkN)_~yXrasRFDVZe`^K^>ULM21x?t@q;qA4SS7G8Hg3W58V%bt82(9% zjKHeddRLt~M3&2KnQOMZN2ZDEao6!gzAs^`C0Jo3Y9TDo2SZM(hztt*YD{ECD3O~a zO%7SvU*lKryo13!Iy^46RB)KN#(QS3%=g4=&LqlP5_~HOSK9K|gsK;fi|%M&+!snz zpG^o|qb(Ea_r|jIMg&7{vRNFf+(zsYNp&lO7sb`1*JKzGduqpJct_kg@eA>x_%*PM zI3+He+(LXJ&NSX+EIQ6Ios|UY<}HhSyy8?!;z~5tCAssdlBh95qhbFZdaAB9@IjD%cNs~CALsi$zt8Xd;G8e_;5|a| zuc9J7p)s-Y?83{=#p1_K7{(>%3f^_~0E=rb7Y>K41rUQVHq4^UJqH{vx~p{^v?b6wPGai%Sv!~jiOEHSmMmA2Beo#XI&U1MuFM3RLxrI^~Vmr1#G zs`u){?FFeeM)mFa9MVTbW?5&8@XRvLMnoxF_f7*}r6={}fUkl&h~jEPO~H9W#+aA} z7X>Hso?;9NHaz9&hm-iw!^0@P_Bh}$e)H7t(k2Mvh`>Y7E_o#UB{npO6_mO}mG+8u zP4^GHBvye@ni9`}(MZS;L&wa=>1r1Dc}0F>@8uv28d-{i@aNH>Ay&mx+qWr=dzZkp zO?`Y-qi*V>#WroA3kmrgg;_^UqB30@$T(W?vTvNLCZ@`q8$bPrCjDk~`5U}tDz*}n zW#-DPbvnFmIV6YWfIRxf+&A5|USfV*;@bP;q`$-PuO&V!z3{V8m=(P96X~XCM(D(i zW`{lN3oIN-PNrLqXMFuLy$M66ym2!O#AH{Zl0C2ka7?NS9@W5E>0;{*EsRK?56o%d zmNaqjJ8<{u!0{UNaplsT$Wwp^(*EccKtgKnx~b_mu-5r9g-}_rCWW-WE2nzJZelCu z4=IF7GL{#4Ag5MJ{Rv?03)d8)s;re`&)xEwR7oyhE2Gj*_W+a*anJ`pNnWm2(9Qk^ DrQ_0z diff --git a/persistence/__pycache__/data_store_manager.cpython-313.pyc b/persistence/__pycache__/data_store_manager.cpython-313.pyc index c33f3fd940a02354c78585b47c59fc26d50186a9..e9eeb01eacd7df810a04ba9da581d3dbc6c656b7 100644 GIT binary patch literal 8281 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 AjQ{`u delta 1269 zcmY*YO>7%g5Pr|QYp?D7@m~_#wH+sM8e2&khd5M3ZD>%Cpx_3yLh50Kwb)B=C&C4#5(f?(dVw=H$ceBBsn_;Uxwz0PZ`MgFR@(2)e)GMVc{6YS zxb$aU8>(uA@JFBiX?rbnS4-2>-MQgrkr>1f-iTa|vS^W{$uu#43~vpX%MpF ztX_R>&D^+VISu2wzzsY5mf~Ucc&g-~Aaja{0W0&=J?50~0Sca3VfH29y5jYf!qYR$bWVYo(QOm(E zA&q9iQj_o~q-L;OPdN_K=viIci}*!?C@<1Am`pBAi9=ljD?la!e0ucwrICa;7=lB7-1_rACKZI@FhbP>#;64+R>l(*dF3I^{>a zqh#Q-@W)h#c%(3Odambnw)p&>9}wP(oTDYU8F_)G;9hjE=(k7h@QZrV9_N2Ohjpb& zE6`U8e8U~(DtKy=Cwr`pCr*<&_!Ic`k83r$=r`9I2?)UJ%jGgM!@O|#ZmcL))q$l(C@7m10&aiEs;JA!UpxVC|;(Psm zhhgs+j?@#{J(pGRa|r<_!&VT^bMT_gj^#LA+x?*5Vr$UJFBIdP_lvtUx@}mqUw9ZD zLjw2nbvRp?c}bM&bl({eT<;5`^{7-nNFKBfGT&|u1aus|^6Ig%W&Gna0|h=TWL}>C zs_ZAXWEQ2HdV5)R3wUWD<-I1EQ243f%e^Ertym^-zW0 bool: + """更新项目数据""" + try: + # 将字典转换为ProjectData对象 + from persistence.models import ProjectData + from dataclasses import asdict + + # 如果传入的是字典,需要转换为ProjectData对象 + if isinstance(project_data, dict): + # 确保params是字典而不是列表 + if 'params' in project_data and not isinstance(project_data['params'], dict): + project_data['params'] = {} + + # 创建ProjectData对象 + from persistence.models import ProjectData + project_data_obj = ProjectData(**project_data) + else: + project_data_obj = project_data + + # 更新最后修改时间 + from datetime import datetime + project_data_obj.last_modified = datetime.now().isoformat() + + # 保存项目元数据 + self._store._save_project_metadata(project_name, project_data_obj) + return True + except Exception as e: + from component.widget_log.log_handler import logger + logger.error(f"更新项目失败: {e}") + import traceback + logger.error(traceback.format_exc()) + return False + @classmethod def get_instance(cls) -> 'DataStoreManager': """获取 DataStoreManager 实例"""