From 28921d68b378961b1d434845d6f3d11187f69a01 Mon Sep 17 00:00:00 2001 From: Sg4Dylan Date: Mon, 25 Mar 2019 17:24:05 +0800 Subject: [PATCH] Update to RC 2 --- README.md | 6 ++- config.json | 16 +++++- core/copyband.py | 129 +++++++++++++++++++++++++++++++++-------------- main.pyw | 37 ++++++++++++++ res/window.ui | 44 ++++++++++------ 5 files changed, 176 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index bbe515b..6588044 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Emiya Engine 是一个用来丰富音频频谱的脚本。可以将频谱变得 ### 当前版本: -`RC Version 1` +`RC Version 2` ### 编年史: @@ -41,6 +41,10 @@ Emiya Engine 是一个用来丰富音频频谱的脚本。可以将频谱变得 - `RC 1` > 加入了参数辅助调整选项 > 尝试在 CopyBand 模式下保护动态范围 + - `RC 2` + > 加入了参数自动加载/保存特性 + > 加入了截止/调制频率的优化建议 + > 提高了系数精度 ### RC 版本使用说明: diff --git a/config.json b/config.json index eac5d46..061820b 100644 --- a/config.json +++ b/config.json @@ -2,5 +2,19 @@ "ui": "res/window.ui", "lang": "chs", "eng": "res/eng.qm", - "chs": "res/chs.ts" + "chs": "res/chs.ts", + "defaultMode": true, + "commOutputSr": 1, + "commInsertSr": 0, + "useSampleOutput": false, + "useOptimizer": false, + "dynProtect": false, + "cbHarmonicHpfCutFreq": 6000, + "cbHarmonicShiftFreq": 16000, + "cbHarmonicGain": 1.5, + "cbPercussiveHpfCutFreq": 6000, + "cbPercussiveShiftFreq": 16000, + "cbPercussiveGain": 2.5, + "akkoJitterDownFactor": 0.02, + "akkoJitterUpFactor": 0.08 } \ No newline at end of file diff --git a/core/copyband.py b/core/copyband.py index 1cf3425..bccdc16 100644 --- a/core/copyband.py +++ b/core/copyband.py @@ -3,7 +3,6 @@ import librosa import resampy - def core( input_path,output_path, output_sr=48000,inter_sr=1, @@ -14,6 +13,7 @@ def core( ): def hpd_n_shift(data, lpf, sft, gain): + sr = output_sr*inter_sr # 高通滤波 b,a = signal.butter(3,lpf/(sr/2),'high') data = librosa.stft(signal.filtfilt(b,a,librosa.istft(data))) @@ -58,7 +58,6 @@ def hpd_n_shift(data, lpf, sft, gain): adp_power = np.mean(np.abs(adp)) src_power = np.mean(np.abs(chan)) src_f = 1-(adp_power/src_power) - d_ls.append(src_f) adp += src_f*chan chan *= 0 chan += adp @@ -80,12 +79,13 @@ def hpd_n_shift(data, lpf, sft, gain): # 参数优化 if not opti_mode: return - optimizer(output_path, + optimizer(input_path,output_path, percussive_hpfc,percussive_stf, percussive_gain,msgbox) def optimizer( + input_path, output_path, hpf_cut_freq, hpf_mod_freq, @@ -93,46 +93,101 @@ def optimizer( msgbox ): - # 加载音频 - y, sr = librosa.load(output_path,mono=False,sr=None) - # 产生 STFT 谱 - stft_list = [librosa.stft(chan) for chan in y] + def envelope_detect(): + + # 加载音频 + y, sr = librosa.load(input_path,mono=False,sr=None) + # 产生 STFT 谱 + stft_list = [librosa.stft(chan) for chan in y] + # 阈值 + t_gain = 85 + # 频谱边缘 + edge_freq = 0 + + for chan in stft_list: + chan_sum = chan[:,0] + for i in range(1,chan.shape[1]): + chan_sum = np.add(chan_sum,chan[:,i]) + + chan_sum = np.abs(chan_sum) + chan_max = np.max(chan_sum) + + # 滑动窗口 + for p in range(len(chan_sum)): + s_win = 8 + s_mean = 0 + if p+s_win 2500: + edge_freq -= 3500 + return edge_freq - # 加载 - l_power = 0 - h_power = 0 - for chan in stft_list: - # 截止频率为 hpf_cut_freq 的 HPF - b,a = signal.butter(11,hpf_cut_freq/(sr/2),'high') - l_data = librosa.stft(signal.filtfilt(b,a,librosa.istft(chan))) - l_power_sum = np.mean(np.abs(l_data.real)) + def hpf_gain_calc(): + # 加载音频 + y, sr = librosa.load(output_path,mono=False,sr=None) + # 产生 STFT 谱 + stft_list = [librosa.stft(chan) for chan in y] - # 截止频率为 hpf_mod_freq 的 HPF - b,a = signal.butter(11,hpf_mod_freq/(sr/2),'high') - h_data = librosa.stft(signal.filtfilt(b,a,librosa.istft(chan))) - h_power_sum = np.mean(np.abs(h_data.real)) + # 加载 + l_power = 0 + h_power = 0 - # 移相差分 - l_power_sum -= h_power_sum + for chan in stft_list: + # 截止频率为 hpf_cut_freq 的 HPF + b,a = signal.butter(11,hpf_cut_freq/(sr/2),'high') + l_data = librosa.stft(signal.filtfilt(b,a,librosa.istft(chan))) + l_power_sum = np.mean(np.abs(l_data.real)) + + # 截止频率为 hpf_mod_freq 的 HPF + b,a = signal.butter(11,hpf_mod_freq/(sr/2),'high') + h_data = librosa.stft(signal.filtfilt(b,a,librosa.istft(chan))) + h_power_sum = np.mean(np.abs(h_data.real)) + + # 移相差分 + l_power_sum -= h_power_sum + + # 合并音轨数据 + l_power += l_power_sum + h_power += h_power_sum + + # 测试 HPF 输出 + chan *= 0 + chan += h_data + + # 频带比例矫正能量比例 + pf = ((sr/2)-hpf_mod_freq)/(hpf_mod_freq-hpf_cut_freq) + l_power *= pf + # 计算当前增益比率 + lnh_power = np.log2(l_power/h_power) * 6 + # 如果是正数,就是增益偏小 + target_r = np.exp2((lnh_power-14.8)/6) + recomm_r = target_r*hpf_gain - # 合并音轨数据 - l_power += l_power_sum - h_power += h_power_sum + #istft_list = [librosa.istft(chan) for chan in stft_list] + #librosa.output.write_wav('kk.wav', np.array(istft_list), sr) - # 测试 HPF 输出 - chan *= 0 - chan += h_data + return l_power, h_power, lnh_power, recomm_r, sr + + edge_freq = envelope_detect() + l_power, h_power, lnh_power, recomm_r, sr = hpf_gain_calc() - # 频带比例矫正能量比例 - pf = ((sr/2)-hpf_mod_freq)/(hpf_mod_freq-hpf_cut_freq) - l_power *= pf - # 计算当前增益比率 - lnh_power = np.log2(l_power/h_power) * 6 - # 如果是正数,就是增益偏小 - target_r = np.exp2((lnh_power-14.8)/6) - recomm_r = target_r*hpf_gain # Tips - tips = '' + tips = '频率设置建议:\n' + tips += f'建议截止频率:{edge_freq*0.4}Hz\n' + tips += f'建议调制频率:{edge_freq}Hz\n\n' + tips += '增益设置建议:\n' tips += f'来源加和:{l_power}\n' tips += f'目标加和:{h_power}\n' tips += f'当前增益:{lnh_power} dB\n' @@ -142,5 +197,3 @@ def optimizer( tips += '建议维持冲击增益,微调谐波增益!' msgbox.emit('优化建议',tips,1) - #istft_list = [librosa.istft(chan) for chan in stft_list] - #librosa.output.write_wav('kk.wav', np.array(istft_list), sr) diff --git a/main.pyw b/main.pyw index 4594b09..59ec8cf 100644 --- a/main.pyw +++ b/main.pyw @@ -47,6 +47,7 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow): self.lang = json.loads(open('res/lang.json','rb').read())[Config['lang']] self.input_path,self.output_path = None, None self.is_started = False + self.load_config() def _bind_ui_(self): self.selectInputFile.clicked.connect(lambda:self.openfile(False)) @@ -67,6 +68,8 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow): QtWidgets.QMessageBox.warning(self,self.lang['MsgBoxW'],self.lang['LackFile'],QtWidgets.QMessageBox.Ok) return + self.save_config() + mode = 1 if self.useCopyBand.isChecked(): mode = 0 @@ -115,6 +118,40 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow): QtWidgets.QMessageBox.critical(self, title, text) else: QtWidgets.QMessageBox.information(self, title, text) + + def load_config(self): + self.useCopyBand.setChecked(Config.get('defaultMode',True)) + self.commOutputSr.setCurrentIndex(Config.get('commOutputSr',1)) + self.commInsertSr.setCurrentIndex(Config.get('commInsertSr',0)) + self.useSampleOutput.setChecked(Config.get('useSampleOutput',False)) + self.useOptimizer.setChecked(Config.get('useOptimizer',False)) + self.dynProtect.setChecked(Config.get('dynProtect',False)) + self.cbHarmonicHpfCutFreq.setValue(Config.get('cbHarmonicHpfCutFreq',6000)) + self.cbHarmonicShiftFreq.setValue(Config.get('cbHarmonicShiftFreq',16000)) + self.cbHarmonicGain.setValue(Config.get('cbHarmonicGain',1.5)) + self.cbPercussiveHpfCutFreq.setValue(Config.get('cbPercussiveHpfCutFreq',6000)) + self.cbPercussiveShiftFreq.setValue(Config.get('cbPercussiveShiftFreq',16000)) + self.cbPercussiveGain.setValue(Config.get('cbPercussiveGain',2.5)) + self.akkoJitterDownFactor.setValue(Config.get('akkoJitterDownFactor',0.02)) + self.akkoJitterUpFactor.setValue(Config.get('akkoJitterUpFactor',0.08)) + + def save_config(self): + Config['defaultMode'] = self.useCopyBand.isChecked() + Config['commOutputSr'] = self.commOutputSr.currentIndex() + Config['commInsertSr'] = self.commInsertSr.currentIndex() + Config['useSampleOutput'] = self.useSampleOutput.isChecked() + Config['useOptimizer'] = self.useOptimizer.isChecked() + Config['dynProtect'] = self.dynProtect.isChecked() + Config['cbHarmonicHpfCutFreq'] = int(self.cbHarmonicHpfCutFreq.value()) + Config['cbHarmonicShiftFreq'] = int(self.cbHarmonicShiftFreq.value()) + Config['cbHarmonicGain'] = float(self.cbHarmonicGain.value()) + Config['cbPercussiveHpfCutFreq'] = int(self.cbPercussiveHpfCutFreq.value()) + Config['cbPercussiveShiftFreq'] = int(self.cbPercussiveShiftFreq.value()) + Config['cbPercussiveGain'] = float(self.cbPercussiveGain.value()) + Config['akkoJitterDownFactor'] = float(self.akkoJitterDownFactor.value()) + Config['akkoJitterUpFactor'] = float(self.akkoJitterUpFactor.value()) + with open('config.json','wb') as wp: + wp.write(json.dumps(Config,indent = 4).encode('UTF-8')) if __name__ == "__main__": diff --git a/res/window.ui b/res/window.ui index f38c814..7e52625 100644 --- a/res/window.ui +++ b/res/window.ui @@ -331,6 +331,9 @@ 22 + + 3 + 0.990000000000000 @@ -350,6 +353,9 @@ 22 + + 3 + 0.990000000000000 @@ -366,7 +372,7 @@ 20 240 - 561 + 571 101 @@ -388,13 +394,13 @@ - 谐波HPF截至频率(Hz): + 谐波HPF截止频率(Hz): - 210 + 220 30 111 21 @@ -407,7 +413,7 @@ - 390 + 400 30 91 21 @@ -422,7 +428,7 @@ 150 30 - 51 + 61 22 @@ -439,7 +445,7 @@ - 320 + 330 30 61 22 @@ -458,12 +464,15 @@ - 480 + 490 30 62 22 + + 3 + 100.000000000000000 @@ -477,7 +486,7 @@ - 210 + 220 60 111 21 @@ -497,18 +506,21 @@ - 冲击HPF截至频率(Hz): + 冲击HPF截止频率(Hz): - 480 + 490 60 62 22 + + 3 + 100.000000000000000 @@ -522,7 +534,7 @@ - 320 + 330 60 61 22 @@ -543,7 +555,7 @@ 150 60 - 51 + 61 22 @@ -560,7 +572,7 @@ - 390 + 400 60 91 21 @@ -631,10 +643,10 @@ - 600 + 610 260 - 81 - 51 + 71 + 71