From bdc2bd9ba750f69a53f1b25a517c3b129fc5a160 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 16 Feb 2025 16:22:42 +0800 Subject: [PATCH] =?UTF-8?q?[feature]=20=E5=A2=9E=E5=8A=A0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=AF=B9=E6=BB=A4=E6=B3=A2=E5=99=A8=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=AF=BB=E5=86=99=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/database.db | Bin 77824 -> 20480 bytes .../__pycache__/db_manager.cpython-313.pyc | Bin 8931 -> 10441 bytes database/__pycache__/models.cpython-313.pyc | Bin 1442 -> 1600 bytes database/db_manager.py | 100 +++++++++++++----- database/models.py | 7 +- .../audio_filter_widget.cpython-313.pyc | Bin 27452 -> 28397 bytes .../__pycache__/avas_widget.cpython-313.pyc | Bin 8854 -> 8927 bytes widgets/audio_filter_widget.py | 95 ++++++++--------- widgets/avas_widget.py | 6 +- 9 files changed, 126 insertions(+), 82 deletions(-) diff --git a/data/database.db b/data/database.db index cc809d3386034af9e63c6ac3261970e3e4845f06..c9cae12b1b9c54f008aa7c66e95e9015a3c4b5ed 100644 GIT binary patch delta 572 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 Jg*RZ7{{@}M*DwG8 diff --git a/database/__pycache__/db_manager.cpython-313.pyc b/database/__pycache__/db_manager.cpython-313.pyc index 651770fd142378147542a58b1d1c951a7db8c7e7..d458632fdf6e0ae681a9901ec08642778099092c 100644 GIT binary patch delta 3667 zcmZ`+X>1$E72f5N%jJD8?_)_yGAYxCq9bv9NIoP>wk%uR(3K*!4rNgaZJLyqij%4~ z=>Dpb7O>Q5YN<(J>Q|NiXcQPoU7#r9rUhJ}Kg8NC7pzgZX#V(5LD@o`wrJ5e%fm`y zkEHMIym>Qkj`zM9{k`}1!}`ZMotl8sUif(Wv%sQWR7+LRJYHX{I7k~(k>`hXynfus z8^+b+CIvL{%($*Y%^O|BIk{lrO;D5ZW~pZ7)#H+Nhn%-a8kV=Z2*Jj)f;~>`Ck00n z5wWA&WEZ)Lz94<%FK^mqa?&^E#M8iqr{biZXqR=8)jCIv7!fJ6s?xfufCWoC?6`zClj-YISs~%L@v2=a$-(3IdNttG5h+*j6uv|$lFk$1LWpA`H(mIJ&?OcNiHLmvW^<+)^fDuL5^qJHoH!$={@6p~E$|_GFliKEp4-E{* zd&8N;g=CaF+pvqEUn$qjPwQLy`B9qr3+{{ltJc%i9>}P1Xr5Z*-aY7hs*BGV;pP{r zcJdiRF!do&SaZe^hQ*ZSXS111PKMVAiv%Hf&<#z9bfM2Q19XTpZW1A6)?N-aLtBIr zc43p<81xvn0W@}KP20{L#tIhTDskUnyOw_^zchQ}^77@ohUhvI6+(#8{m0Y6_YU?R zeuYa-M!B!<4ASd8WGC9L_tAKQ!VBo6-bDt`IejPDhYI?DeB>@WihifhYD~~B9ULP= z-G+?%ECdTr>>@g3=rybLz?c%+r4pC(GJJF(shX76q@pJ2np9%RGka)MG&t?5IN3pV z;@yFgp>`1&I!?t@=%Utwj7C+y|2U|XaXO}{nry|fdgu~yWzDUUuew$8RkupM>Q>21 zZoy8C-H#dSoc>CJ zotC!gMXzya?xWgyKrBq9rXh?Qp^7TjCN!*MQ4ga)zh=y+nYBROias#3@u6qR^o!V4JoVguDo zLP%UVBV^w!)A-YWAy-z`oC*8DB8SJ}Y6Zw7W!jO4*dcOzfL^W=qRv#(aYY?>PZumq zK46{K#}~&dGMTBXLK9~9g7&dWVbjm|RkVcDf5WhBxa)|_4~Paw(ZGpz_fl-(ttTv@ z4;6L6O&4MFi>^@N;Br)SHx-7L_lch7LSlJP479Gct$4)X_SJ(cQ88bY8#<*lvX!v8 z>Rt!Puer55=Z}hZ@Adp*{?GRC0wo&l*Y%6~_vb`^u+X-AN#wxe3N1Q4OT)`H(dJwV zEKb#HF7Hxex#hlxD_9D{E4KFrMK4##o0db6zqy1D(HwnMZy7rLK}lCaW}E(pK>&Y58o7h4avQ@0g|nm~Nku0BF4 z%W_OBQaA{sU?IE;a27{pz32%zYl%FTFnKgninsy|>1^f^bBC;v@ie5i9Q{pZi6}>M zX>2Z)xFXj0uIqp`WWWtH`q*uus2GDKNudol3pH&`tH*LL6*E5VRsZUs>s~qFDGSkm z4XA|~dF#tw(N)?ik25tlOw|p=#LSWdCT6Wk8OP;!4prSd zFdU6OaE~JOGp;(31KlO0q9C)JyD49;+kfEvczWCvvlpR;fuTqpK&{2lEz=V(7;( zfB_hf5QZ?E#Bd73FoqZg9>XgDW%_LP!iCf<SC5yXhl>rhy!$mf{y1mqTpxAn#qL8sYR#1NqvJ=UU1$MqL{^sV++8Nm zH{KTLma~U^AN|WY_!6exviw{&l_|^5C%>Jm(lC7~k$xkY6JEpJ>FW7RVoUn`n+ah$ z2Ty@3t{^-G3a&QtCpZ7-Iwd>YAaUVYK_QJK-@@1u7hu}X;cE(?BOGDU+eWUS>)v-X zcsUX$d_n*x1ksRBmp=seaUV!$+DZx!XO-)nqs=ens7?m#E>AK|*?35J0 z&su*sYV(Jp(lreimt^+bJdskQ8>RiNu83UN593#FLws=w69AwMqmTVBTJS5etV?B5 zvr%_WVEf$LBDy`I$1et %Z2b@|}x z@#*J>Hf@B-E&4f;gBbV2)dANAw2EGz=nHO`R3`JLb&G{pw7I`#QL(ez{rdTnmE91l zC9S8Z^{jh$tX^E(`6q3xGC&eWyAXn@NwFz3qZ{0@!3eHDEB8z3-0v&a1`#k@fbG;*QZx z+*J7%=~H+MRD}SsW|73LlqA+;r`NxcD8?qLwdr%4*rw7$Dikhc4tgBh6g*iWFjn^j tPcfnscA>uDF&9qWs#-c{X5WSEo zgd2Yh+u%F+D_8}8zU5~)$c$U@I_oqnn6!xj!0)n^%$Ohl+v>wVVEvWsNP(M5FQ->3 zD4tI%(~VQ-6K4DwJB||^CeD7v&BGns!M7S2;)A8(NAcgKNL&Il;07E?z=AlNnO#0t zc5nk0IAwa_q5_Gngd~jldZ(GlZ-Ttul+*iEz3-krfWlj!@%tb*!I7wXjP*FCQ}Cy{ z2Harm##8!NFmLz+j_SMdqVdv}rJ@;{Pv!NiR<0H!K0zf`4qO66oBh3IE#SgAy)STH#S_wN`UO+pb~UYF#oKNWZp6Blu>p z2H&+N<8h**C0zl)gsvn5km6)U1{`Pur=Scne2T%Fl`aRHf-SI>E{l{5n_|Zd^sL$( z;EbR!`+>qZz#v&cMwlS(N+l(fU5zrsRsbr11TwmeF#Zz$uHCIy7>Nwa2)N4O#o2}BX{0E0tn{R42UncBbGz zp2qLHysO8FnR1-~VU1|ZiIOTxcg1jaD(~`Mn_QpFTf6c$-xbp%o^_ko`ipwt4ZUyq zk!9PHSWDhNciBb*ggSL1ExTK`UY-0*YbI*xp>dUN$|`{1@a`TO?4P4?>gKeX`_-Ns{4U4f%iLcPQg(ZyZh2$YLR1dTQVIgTHK6u@6dA(l&V zloa@HRx`_|cx)4#Tt?88Zf5*E?yv4?V8+TXW7T(ZtG6vBTGl$9#)yV&yvi*w=wsX9U;#2i=K;We;}^3u$GU zP!a#cF@QgCwj~R~g{8&C+2t~M2S`lMj^r7Q5oL9uqQqG(vpvUK91S!~q==F7If4Jn z(e}K}bw#(Aqd8Ap^~BebJ0|OULvIfi8OGL76oB2I3pA>M#!Vr2U_d=EfIkXESFO%# zrgalBadiDtTdFK18YqAhB)Wph5)HlVf*5OvNKS6%Uq zeYv_LYTc0{&$znb7Y3cp{(uEiZP5ut+j}S9KKagY-Vu1*N+_HY!{qx?p;TJ$t?WI> zess`y9D=QPgIA&R21qakrtv@l&Oc4KxHHrZm+?wysDq}80ynobn<;Sf)2}O~v?08j zUbsB1Ai75+pJ=J#EVUHoUrVDIg(T5`g~B9>R!dC~ZOPIo)B7~(pcBLroun{CVVHvE ziQAKOw5vojk3z2!O)2ED`8?bNU&o%v_n)QW>-4$8zl(^gBzaBHYo-+$KKU`7T!xvT zFK|iE%ACxTK0(%X@_Y1p*&rLs`uz;a&S30mJ}-|Z&v?anr1i-xZ1!Dqxg(f&`}cGdZI+OE?Nl*JSd}vcR8!ziuwmnk zd!|!GYbUT)qA(3`@P0zCxfmw2MKY8CRqhe9=Pd)N;lPc9bA_rk0*JEvAR?E=~;8ZCSz zD;EK&Hd31%w~}ge|0moh-%tm~?=+9A4QF?0S2678gITr+NVRcRt8P1QʧHTljN zVn(`(T|Dp0D!YJGMRNs@*|^OU;zwZ-P%N#ThL{jhBd(91@M#;NZHYwG1^wa0rK!sc X(?`&E@RfMn_Du$k!iPYsw9)?oJs?|= diff --git a/database/__pycache__/models.cpython-313.pyc b/database/__pycache__/models.cpython-313.pyc index b51b524fa2571d27fbcd70803afb189ff745c4bf..3abf0a6aa89b26a7c8c3ff5b54d48cffb938f2d8 100644 GIT binary patch delta 886 zcma))!E4iS6vvzN*CtJxwO!M$+SW}wa2*r8$fS%NRNRWv={och2x*(uK%2;~5xhtX z0qwxUn;IdA6h;rrhEz4v?X{qj!!m{g7xMT*d` z_4-5i@Rjn5dqd{X%23c^O>~+1HBhlr6+cx1sHTWTEkREtm?dFJL)4O)mBg}^)KCnn z#G1;9PdVe8W4;ug>n5w|P`YjPTod0iTqAP?S)tT^WZ1UZ)2$A9$yKiGg@S1tt)AJz zJjBJv&cJdl$8Lm)wqx&GU3xO)tl>EshACaARUFrVlLK83qXQR*vHhN7 zxHtoKP|I<8c%Dj}1;FK4B{jat<;VlR_V7M+yoh{HXT6;uqxwh?;O9%c`eFQ|l<$S3{+w@ZHT zD`br;SG73Z(`>IoH&K9s$wYJWUs>dXYHsoJw&$AH?a&-YGc!I&5ll=;{OIJK?7$7x(+s*XcZIy zZW_Q^=tQFIZ3U9z)u&^nv(I;?OIRh}P;HrQfhGRCo>1KAJDn#za}!@B>#<99i7QVc l6vxpBFHd+d3sn8);}D=Y34obq0mP}32n7rL9>#{6qm!Q3TLn$J;xno9H(J9JF1@}n%%M0FhEbYkd6XwvIt;@?-|uHp4rSR_uq4gl zEIR%u%la@c4(Jl8h*xyeydj^TYhT1yx){vOk8V%cxHa`_qwUGV54<+@tD}39y-&Of zfw;l~@sh7>aLLV(w1bYHI$hBlU`TqaC_RWE8YuX(IAqP8itK1LOz`C&swfL6=TH_= z>L|-7SPB8k3d-t<;5I|7MdDpvGgQs0xXS9}8Xo(=IAuep*xEXnJ)>b3_EwheCq0Fv zrmExcG#bQ(y$5lW$K6og>=@MgFX$4YD9{?Ze`(k8aqUEK$Pn)?aV=-OJ+-}Yb6T!E z+c{otO+3{%FRJZS&);ho*3CiIebSF_!MgaUpKn@ZVWvqrVj6X36hmLSUzC&OnI`2= U0z+3N81ZMC6qWcvrBj1{1IA93f&c&j diff --git a/database/db_manager.py b/database/db_manager.py index 3d76dde..3f4d7c3 100644 --- a/database/db_manager.py +++ b/database/db_manager.py @@ -14,13 +14,14 @@ class DatabaseManager: app_dir = Path(os.path.dirname(os.path.abspath(__file__))).parent data_dir = app_dir / 'data' db_path = str(data_dir / 'database.db') - + print(f"db_path: {db_path}") cls._instance.db_path = db_path cls._instance._init_database() return cls._instance def __init__(self): - self.init_database() + # self.init_database() + pass def _init_database(self): Path(self.db_path).parent.mkdir(parents=True, exist_ok=True) @@ -30,22 +31,27 @@ class DatabaseManager: CREATE TABLE IF NOT EXISTS configs ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + channel_id INTEGER NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(name, channel_id) ); CREATE TABLE IF NOT EXISTS params ( id INTEGER PRIMARY KEY, config_id INTEGER, + channel_id INTEGER NOT NULL, delay_data1 FLOAT, ENC_volume_data1 FLOAT, ENT_mx_right_data FLOAT, ENT_mix_left_data FLOAT, - FOREIGN KEY (config_id) REFERENCES configs(id) + FOREIGN KEY (config_id) REFERENCES configs(id), + FOREIGN KEY (channel_id) REFERENCES configs(channel_id) ); CREATE TABLE IF NOT EXISTS filters ( id INTEGER PRIMARY KEY, config_id INTEGER, + channel_id INTEGER NOT NULL, filter_type TEXT NOT NULL, freq FLOAT, q FLOAT, @@ -53,7 +59,8 @@ class DatabaseManager: slope FLOAT, enabled BOOLEAN DEFAULT TRUE, position INTEGER, - FOREIGN KEY (config_id) REFERENCES configs(id) + FOREIGN KEY (config_id) REFERENCES configs(id), + FOREIGN KEY (channel_id) REFERENCES configs(channel_id) ); """) @@ -62,51 +69,84 @@ class DatabaseManager: def get_all_configs(self) -> List[ConfigData]: with self.get_connection() as conn: - cursor = conn.execute("SELECT id, name, created_at FROM configs") + cursor = conn.execute("SELECT id, name, channel_id, created_at FROM configs") return [ConfigData(*row) for row in cursor.fetchall()] def load_config(self, config_id: int) -> Tuple[Optional[ParamData], List[FilterData]]: with self.get_connection() as conn: + # 1. 首先加载参数数据 cursor = conn.execute( - "SELECT * FROM params WHERE config_id = ?", + """SELECT config_id, channel_id, delay_data1, ENC_volume_data1, + ENT_mx_right_data, ENT_mix_left_data + FROM params WHERE config_id = ?""", (config_id,) ) param_row = cursor.fetchone() - params = ParamData(*param_row[2:]) if param_row else None + if param_row is None: + return None, [] + # 2. 创建 ParamData 对象 + params = ParamData( + config_id=param_row[0], + channel_id=param_row[1], + delay_data1=param_row[2], + ENC_volume_data1=param_row[3], + ENT_mx_right_data=param_row[4], + ENT_mix_left_data=param_row[5] + ) + + # 3. 加载滤波器数据 cursor = conn.execute( - "SELECT * FROM filters WHERE config_id = ? ORDER BY position", + """SELECT config_id, channel_id, filter_type, freq, q, gain, slope, + enabled, position, id + FROM filters WHERE config_id = ? ORDER BY position""", (config_id,) ) - filters = [FilterData(*row[2:]) for row in cursor.fetchall()] - + filters = [] + for row in cursor.fetchall(): + filters.append(FilterData( + channel_id=row[1], + filter_type=row[2], + freq=row[3], + q=row[4], + gain=row[5], + slope=row[6], + enabled=bool(row[7]), + position=row[8], + config_id=row[0], + id=row[9] + )) + print(f"load_config filters: {filters}") return params, filters - def save_config(self, name: str, params: ParamData, filters: List[FilterData]) -> int: + def save_config(self, name: str, channel_id: int, params: ParamData, filters: List[FilterData]) -> int: with self.get_connection() as conn: cursor = conn.execute( - "INSERT INTO configs (name) VALUES (?)", - (name,) + "INSERT INTO configs (name, channel_id) VALUES (?, ?)", + (name, channel_id) ) config_id = cursor.lastrowid + params.config_id = config_id conn.execute( """INSERT INTO params - (config_id, delay_data1, ENC_volume_data1, ENT_mx_right_data, ENT_mix_left_data) - VALUES (?, ?, ?, ?, ?)""", - (config_id, params.delay_data1, params.ENC_volume_data1, + (config_id, channel_id, delay_data1, ENC_volume_data1, ENT_mx_right_data, ENT_mix_left_data) + VALUES (?, ?, ?, ?, ?, ?)""", + (params.config_id, params.channel_id, params.delay_data1, params.ENC_volume_data1, params.ENT_mx_right_data, params.ENT_mix_left_data) ) for filter_data in filters: - conn.execute( + filter_data.config_id = config_id + cursor = conn.execute( """INSERT INTO filters - (config_id, filter_type, freq, q, gain, slope, enabled, position) - VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", - (config_id, filter_data.filter_type, filter_data.freq, - filter_data.q, filter_data.gain, filter_data.slope, + (config_id, channel_id, filter_type, freq, q, gain, slope, enabled, position) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", + (filter_data.config_id, filter_data.channel_id, filter_data.filter_type, + filter_data.freq, filter_data.q, filter_data.gain, filter_data.slope, filter_data.enabled, filter_data.position) ) + filter_data.id = cursor.lastrowid conn.commit() return config_id @@ -137,29 +177,37 @@ class DatabaseManager: if not configs: # 创建默认配置 default_params = ParamData( + channel_id=1, delay_data1=0.0, ENC_volume_data1=0.0, ENT_mx_right_data=0.0, - ENT_mix_left_data=0.0 + ENT_mix_left_data=0.0, + config_id=None # 将在 save_config 中设置 ) # 创建一些默认滤波器 default_filters = [ FilterData( + channel_id=1, filter_type="PEQ", freq=1000.0, q=1.0, gain=0.0, - slope=12.0 + slope=12.0, + position=0, + config_id=None # 将在 save_config 中设置 ), FilterData( + channel_id=1, filter_type="HPF", freq=20.0, q=0.707, gain=0.0, - slope=12.0 + slope=12.0, + position=1, + config_id=None # 将在 save_config 中设置 ) ] # 保存默认配置 - self.save_config("Default Config", default_params, default_filters) + self.save_config("Default Config", 1, default_params, default_filters) diff --git a/database/models.py b/database/models.py index 3be871d..8ceb411 100644 --- a/database/models.py +++ b/database/models.py @@ -4,17 +4,21 @@ from datetime import datetime @dataclass class FilterData: + channel_id: int filter_type: str freq: float q: float gain: float slope: float - id: int = None enabled: bool = True position: int = 0 + config_id: Optional[int] = None + id: Optional[int] = None @dataclass class ParamData: + config_id: int + channel_id: int delay_data1: float ENC_volume_data1: float ENT_mx_right_data: float @@ -24,4 +28,5 @@ class ParamData: class ConfigData: id: int name: str + channel_id: int created_at: str diff --git a/widgets/__pycache__/audio_filter_widget.cpython-313.pyc b/widgets/__pycache__/audio_filter_widget.cpython-313.pyc index 3f1011a05e333ea9fce48276a2c638499e3d0758..4993e0d2df02bbba590eba8ac731b85ad4111e9d 100644 GIT binary patch delta 6329 zcmai232+iK0!45-ACUE~+6R5~3i20KEW3MH-t* z;4Meq6A9CM!y_t%Jtef<5l$EVWIk~^(L=U z)QmSop)pZAdMpr$1jA4!*SNkim0$)!(KI?O2*F5v_yJ|sMw2vxXk}N9>;&R7 zOv+L8Y-XyaVNSlH&QFz;;=3T_EuWJ=tH0$cOW7Q$Y-cjNDv@24%5kRh_*A|Nes>Kj zw-#u0t45}*Vov_1+I1hf6ta;8r4Woy3lUPFx3LSvB=6*g6y)_{M}?m|Qp7L^_y^KC zP!pEpKzt4uAIQSb5z`UNEC@s;bu!F2H!kza`%hWJ(ZE=Gcl^;%I35&Yt^D9)UbQ3u z-9!DNVoC@_;(`k%5qN}rgdBtd0Iysq#4@t|fGCD6@$jewV3!ff$j{`iTBM2X1wg6g zU#-4eopdxN9F4DrmK|HpX3i;ZsSQg;&;0oO!KIAq6?F~CP-M3hS0sy@62(n(+gJ33 zDRXuz(;}3>B%(YLm<*0?C=E2>(WBbjFNRaUNS-LlCSO(BxG+a5n(}RCrl*2oBHTmz z#DbJ+Z5CpzD>C_k4#v`FR~5tP$n%vBa#&;L4j9RNkp-tB4NbP$#Z7yZYTK2zxxQO^(~_n6x-;1_kZ2iL zYTmt+wP!`YH|6mrJ#7gOP`ssg-&HWVrK?KDXgN1~b~c$=mdGqyXh_!fBx-y9x#(v3 zzmzZSA4={YP3#|C&Kz4(kHI-CwkjK0mM2rHDjQXVI^O$hnq=Nd;LU9T1E zn-SUoHWW`1Q75ce$kvi-?P(Y4j8`e01Jz-a9F@ML*Dmr;+N~ZBG>S6Ncu{^N8Vw6& zv>uBKLN$^%BXp7qU7ix>6N<=y&e3a7RLpm-G4NW=*C?#>zEuWZ3xjL;TD2(^L3UoY z%HVrJwnpEpMulQKJ72%X;QONtonn9$O306NA+}>NSN{yhddQz;OtXc=p4lRa&qEGm z=Chq-Ci5TI64Gk)6<=ffy_~QQS=6O1)L`&r{2EIYD2ApFbcOttv6bCNR*m^}R0b>^ zA&f#V-1x1yjco{B2-^`*2*Oc>9A*zbj98p`FJ1{5q{5rFpfNpfb;iuDPrO1RPgtWqPzb* zpEK9l6HO`C#>uPB0s}q5Y)QgVa?4q+JP53a7IN2RA+Fpf*#qQi z?x-yYjr7PyBvDTxQ3;BgROOl2k;N@}S6H}zZ|6^NHOQOrO@wEVOq`Xj1zf((1A*g5iT&viJ0q}YL*-z zN`At61uIm%T2U4Y#vhUrl8D+^JRrnlGokn~p_|jsWm_^?(6<-GF+tnGR(2URHY+xH$)j+=un`IHsPqyx`lART% zQr0iaVCrQN`H)VcWf;F4LM0jg4dLAM@smBgmHeyKg7dRd?Y(|Wx-@&lqVvgpj8D;` zjVRV>twhsoCcm!8BtG6ufSS})s#RlPl6^{v2F7VJ7@rE(Pq%!`TQdFN9;8)yW}r@@ zgm#%vy|FHMUlY+(T1W_1m~Ge3Lg1$97k&uC#-*V}ThfKq&OxtMpu&$sm+&OQEW+0S zMDaog!i$f(#L-? zvy?w@UY9ajE@>}llg8qNv3UOUo5p&GGfYJcPI4jH}yrUos8a2 zZL8!0cGg_v4(H(+;8BT;HOo*v7Mbp;lu~76enwabljg1H6ckUsRc%Ny!Pm1&=+p8SJAM97y zi_8$TOV6O3D4X7w4T34#ZMAY?9bpXx>cS;UKEk*epQA_z$ zvZOgt(!649A^+Ic4K_*J{`Cs9Ne~WEL-qpl)`<`VSP%KJehWa%BQI>TD^7%hGa2Nq z_G&3qze;o+cCJQF`fIAlU`JLye0|{{aNr)e>LGMV^l44M$~V3zLZ1(mSspqrnXw)o|wt`?M8BCi-G<8Oh6`2lkLscJ_iQ3ttlStVgg{ zks9;ujc^>5KPJcEbSt#VEWpJC1$ zo||~?50)~@SJV~n+KQKLrR0NcwVl^DCpY)Q@6X*YSH4)8bT|FN-Lx{eFF6=U3e z6N$lz6?HhJHYe52gxYzfYhIV+n-YA}a&GgAx`kABB|wMocH2qL_WwIX^;rGDkBd6k zCnOzR(P{YN^r$}Q6hUli#CXAQv>W|42-Gyu+x!64fDbC&Q zI5*LNV=|-@azk0l`KgG{LRD15(lj@aTqqUvA0ZtLF`vcKEW#fnd<_5t2P~t=rNlD5 z_zPsI$HSJAk9&R!i~oJ^8{912s6krXg@fq2-^S7^0`=r}D2cjoC=%=*gG{)#hJFfp zxTT(c7kRj)j(#Nh!qrE6AQo)cD)RC+BQfq$vNa@o*9sf}B-cOcKdInk?BXfk({iPx zX+(aYq3FMmpF0RT1PpJ4_YmGkK>H?qxOn)$b=FDKPE#~8d@L9k3kt)d;Sg#v<~F4I zPzR(nue9fqZynOHO^bheNXvmRUOYU>tuJO7E)Pr7;hg`ozJ#a{&|HgZNGz!yh;r29 zbjBnaAdU`!-+`|MW5JVx7j#(EM1nKJkY|Br&`VGUjWH!mh-$wcQ5TcfhD+H$B;xQ5 zVC1C{zrsN;*$;4GE5d&u{3pV%i1ldoEY5{)GCVyQ5#@2bn;&EEBm$2>C!jZ-o?2R<^*h*H8 v*ETh>1MFP}aV^5y+0yefYYe?sfY!7By)I# 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 diff --git a/widgets/__pycache__/avas_widget.cpython-313.pyc b/widgets/__pycache__/avas_widget.cpython-313.pyc index 03be3996f5f2220ae6606f5ad34feb47f12d8d3b..8df9d26d00e7e47050bda297cd3c35b7dc1a5683 100644 GIT binary patch delta 1608 zcmZuxU2NM_6!wkn)JhiHjhiNIvc_q)Hlef|L+L<_szvQa*U?pRv%|_#+VTaqM~K-K}%)Yz4k1Ok*tqnWOAdBsgK`1@K(ZY;-TRd?O8Sq**;YEi)@*Exe@0&Mx1 zl@G&4EChFBTJe9BeQpawbW2%T!1cCC^0vigH_pVw+;z)3Vj$1UBo0%(8eHciij?7< z44upIS=-OEYLpG%@bXeiiLZ^RIcl2{e_OoUWo1eR-F3^}r{tOtfj5L*U5tOw=D#ke zj#B1PVO`wId$Rjcd6IXzm})NDJcKreVSB>gLjFjHLl$yEb5w~nj+3-aSQmSUQ+P|1 zA>r+Te?&FZ9Ja0fsGXnj21A`TdekOg^~#}6!?&WHggc#YdF6B`-m#Vjca?nz+1M5x zVw1$`(_M3XyuTq@wKbDAq(Y%oDOC%FhX45&mn#*sT&UDm;F|AWktSIO_{@JL@;JLT zf3I^tN`be!wx!69)c;d-Xh(|FvwNmJ;wHN|@4;Oq98T?07EiJ-clWd5xEvJvLV`ga zCGfqR1dpb94G*3Q%qwGp%o#jPC`tH8iNb5l{-ErIuarKx`@t!e(vXX)OJ`S==Eyo`YVPm2GkhO}HP&Q{G8ixEx5BVme>mSUexNiA55Q*su5 zi4T*lx?h*bi6=2}7U4L;90J}4io?+}2xk#aAUuUI&%i#hNk`-YIuR@=Bu2;ryq&lj yx1DcdWC8(?wjmu^SuNJe<^;V6lY`@WiI9UE$L?`x@15dL6B61O{*yy%SN#Vjq9-%} delta 1338 zcmZuwO>7fK6rS1juASJs>)0$dF|pU#2FEdlKx2XsilU1DpAxN;Ho^r5QP(vJ#va>> z)Lx=qAb=3?5WR5d1*r#GKt6#42e@#Ji27rYK*|ACJvMDYRin-rFHmiV?T@u%5cDrOi69MJhnBh*jh?% z^D8hbhT%VL9gI0N+5_|5evw!~xGb8@9n6VAcp-Y)>UXx~Yj)MP`tCNr7tT1|uOEhc z4jnEz)Ri7(M^NiXuH1`3_#N0xRJbhlh=OGzGbn~V0b({|O-Q`e8N`RbZ!T~J=x4FE?S{S#`7B@f;@r%5zA~L?r0(LJs>Mt-9~W2>uKTxAR(s;#DbfM>cm0_1A(q*~ zA+B=wWZ*VU!E#^&ov8(buLSxjyzL&A(-<@W$xtNO2$dL~sV;rVPMyuNVf0R+fu1Sj zH!yHD&-yu4{vWmg1KI!p diff --git a/widgets/audio_filter_widget.py b/widgets/audio_filter_widget.py index 83b46fb..5b8b5ab 100644 --- a/widgets/audio_filter_widget.py +++ b/widgets/audio_filter_widget.py @@ -8,8 +8,11 @@ class AudioFilterModel: def __init__(self, db_manager: DatabaseManager): self.db_manager = db_manager self.current_config_id: Optional[int] = None + self.current_channel_id: int = 1 # 添加当前通道ID self.filters: List[FilterData] = [] self.params: ParamData = ParamData( + config_id=None, + channel_id=self.current_channel_id, # 设置通道ID delay_data1=0.0, ENC_volume_data1=0.0, ENT_mx_right_data=0.0, @@ -19,15 +22,22 @@ class AudioFilterModel: def load_config(self, config_id: int) -> bool: params, filters = self.db_manager.load_config(config_id) + print(f"load_config filters: {filters}") if params is not None: self.params = params self.filters = filters self.current_config_id = config_id + self.current_channel_id = params.channel_id # 更新当前通道ID return True return False def save_config(self, name: str) -> int: - return self.db_manager.save_config(name, self.params, self.filters) + # 确保所有对象都有正确的channel_id + self.params.channel_id = self.current_channel_id + for filter_data in self.filters: + print(f"save_config filter_data.channel_id: {filter_data.channel_id}") + filter_data.channel_id = self.current_channel_id + return self.db_manager.save_config(name, self.current_channel_id, self.params, self.filters) def update_filter(self, index: int, **kwargs): if 0 <= index < len(self.filters): @@ -162,39 +172,38 @@ class AudioFilterController: return next_number def add_filter(self): - # 检查是否达到最大滤波器数量 - if len(self.model.filters) >= 20: - print("已达到最大滤波器数量限制(20个)") - return - - # 显示滤波器类型选择对话框 + # 1. 用户界面创建 dialog = FilterTypeDialog(self.view) if dialog.exec(): filter_type = dialog.get_selected_type() - - # 获取下一个可用的序号 next_number = self.get_next_available_number(filter_type) - - # 创建新的滤波器名称 new_filter_type = f"{filter_type}_{next_number}" - # 创建新的滤波器,使用默认参数 + # 2. 内存中创建 FilterData 对象 new_filter = FilterData( filter_type=new_filter_type, - freq=1000.0, + freq=10.0, q=1.0, - gain=0.0, - slope=12.0, - position=len(self.model.filters) + gain=1.0, + slope=1.0, + position=len(self.model.filters), + config_id=self.model.current_config_id, + channel_id=self.model.current_channel_id, + enabled=True, + id=None # 初始创建时 id 为 None ) - # 添加到模型中 + # 3. 添加到模型的过滤器列表 self.model.filters.append(new_filter) - # 如果有当前配置,保存到数据库 - if self.model.current_config_id: - self.model.save_config(f"Config {self.model.current_config_id}") - + # 4. 保存到数据库 + if not self.model.current_config_id: + # 创建新配置,使用默认名称 + config_name = f"Channel {self.model.current_channel_id} Config" + self.model.save_config(config_name) + else: + # 更新现有配置 + self.model.save_config(f"Config {self.model.current_config_id}") # 更新视图 self.view.update_table() @@ -231,7 +240,7 @@ class AudioFilterController: pass class AudioFilterWidget(QWidget): - def __init__(self): + def __init__(self, channel_id: int = 1): super().__init__() self.ui = Ui_Widget() self.ui.setupUi(self) @@ -242,38 +251,16 @@ class AudioFilterWidget(QWidget): self.db_manager = DatabaseManager() self.model = AudioFilterModel(self.db_manager) + self.model.current_channel_id = channel_id # 设置当前通道ID - # 加载配置 + # 加载该通道的默认配置 configs = self.db_manager.get_all_configs() if configs: - # 有配置则加载最后一个 - last_config_id = configs[-1].id - self.model.load_config(last_config_id) - else: - # 没有配置则创建默认配置 - default_params = ParamData( - delay_data1=0.0, - ENC_volume_data1=0.0, - ENT_mx_right_data=0.0, - ENT_mix_left_data=0.0 - ) - - # 创建默认滤波器 - self.model.filters = [ - FilterData( - filter_type="PEQ", - freq=1000.0, - q=1.0, - gain=0.0, - slope=12.0 - ) - ] - self.model.params = default_params - - # 保存到数据库 - config_id = self.model.save_config("Default Config") - self.model.current_config_id = config_id - + # 查找当前通道的配置 + channel_config = next((config for config in configs if config.channel_id == channel_id), None) + if channel_config: + self.model.load_config(channel_config.id) + self.controller = AudioFilterController(self.model, self) self.update_view() @@ -287,10 +274,12 @@ class AudioFilterWidget(QWidget): def update_table_row(self, row: int): filter_data = self.model.filters[row] + print(f"filter_data: {filter_data}") # 创建带复选框的滤波器名称项 - filter_item = QTableWidgetItem(filter_data.filter_type) + filter_item = QTableWidgetItem() filter_item.setFlags(filter_item.flags() | Qt.ItemFlag.ItemIsUserCheckable) - filter_item.setCheckState(Qt.CheckState.Checked) # 默认选中 + filter_item.setCheckState(Qt.CheckState.Checked if filter_data.enabled else Qt.CheckState.Unchecked) + filter_item.setText(str(filter_data.filter_type)) # 设置文本,这样文本会和复选框一起显示 # 更新各列的值 self.ui.tableWidget.setItem(row, 0, filter_item) diff --git a/widgets/avas_widget.py b/widgets/avas_widget.py index 02851cc..a0d867e 100644 --- a/widgets/avas_widget.py +++ b/widgets/avas_widget.py @@ -9,6 +9,8 @@ class ChannelButton(QWidget): def __init__(self, channel_num): super().__init__() + self.channel_num = channel_num # 保存通道号 + # Create GroupBox for the channel self.group = QGroupBox(f"CH{channel_num}") layout = QVBoxLayout() @@ -98,8 +100,8 @@ class ChannelButton(QWidget): def show_filter_window(self): if not self.filter_window: - self.filter_window = AudioFilterWidget() - # Set window title to include channel number + # 创建滤波器窗口时传入对应的通道号 + self.filter_window = AudioFilterWidget(channel_id=self.channel_num) self.filter_window.setWindowTitle(f"Channel {self.group.title()} Filter Settings") # Show the window if it's not visible