neverlib 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. neverlib/.history/Docs/audio_aug/test_snr_20250806011311.py +0 -0
  2. neverlib/.history/Docs/audio_aug/test_snr_20250806011331.py +75 -0
  3. neverlib/.history/Docs/audio_aug/test_snr_20250806011342.py +57 -0
  4. neverlib/.history/Docs/audio_aug/test_snr_20250806011352.py +57 -0
  5. neverlib/.history/Docs/audio_aug/test_snr_20250806011403.py +57 -0
  6. neverlib/.history/Docs/audio_aug/test_snr_20250806011413.py +57 -0
  7. neverlib/.history/Docs/audio_aug/test_snr_20250806011435.py +55 -0
  8. neverlib/.history/Docs/vad/1_20250810032405.py +0 -0
  9. neverlib/.history/Docs/vad/1_20250810032417.py +39 -0
  10. neverlib/.history/audio_aug/audio_aug_20250806010451.py +125 -0
  11. neverlib/.history/audio_aug/audio_aug_20250806010750.py +138 -0
  12. neverlib/.history/audio_aug/audio_aug_20250806010759.py +140 -0
  13. neverlib/.history/audio_aug/audio_aug_20250806010803.py +140 -0
  14. neverlib/.history/audio_aug/audio_aug_20250806010809.py +140 -0
  15. neverlib/.history/audio_aug/audio_aug_20250806011108.py +140 -0
  16. neverlib/.history/dataAnalyze/__init___20250805234204.py +87 -0
  17. neverlib/.history/dataAnalyze/__init___20250806204125.py +14 -0
  18. neverlib/.history/dataAnalyze/__init___20250806204139.py +14 -0
  19. neverlib/.history/dataAnalyze/__init___20250806204159.py +14 -0
  20. neverlib/.history/filter/__init___20250820103351.py +70 -0
  21. neverlib/.history/filter/__init___20250821102348.py +70 -0
  22. neverlib/.history/filter/__init___20250821102405.py +14 -0
  23. neverlib/.history/filter/auto_eq/__init___20250819213121.py +36 -0
  24. neverlib/.history/filter/auto_eq/__init___20250821102241.py +36 -0
  25. neverlib/.history/filter/auto_eq/__init___20250821102259.py +36 -0
  26. neverlib/.history/filter/auto_eq/__init___20250821102307.py +36 -0
  27. neverlib/.history/filter/auto_eq/__init___20250821102310.py +36 -0
  28. neverlib/.history/filter/auto_eq/__init___20250821102318.py +36 -0
  29. neverlib/.history/filter/auto_eq/__init___20250821102507.py +36 -0
  30. neverlib/.history/filter/auto_eq/de_eq_20250820103848.py +361 -0
  31. neverlib/.history/filter/auto_eq/de_eq_20250821102422.py +360 -0
  32. neverlib/.history/filter/auto_eq/freq_eq_20250805234206.py +75 -0
  33. neverlib/.history/filter/auto_eq/freq_eq_20250820140732.py +75 -0
  34. neverlib/.history/filter/auto_eq/freq_eq_20250820140745.py +75 -0
  35. neverlib/.history/filter/auto_eq/freq_eq_20250820140816.py +75 -0
  36. neverlib/.history/filter/auto_eq/freq_eq_20250820140938.py +77 -0
  37. neverlib/.history/filter/auto_eq/freq_eq_20250820141003.py +77 -0
  38. neverlib/.history/filter/auto_eq/freq_eq_20250820141006.py +77 -0
  39. neverlib/.history/filter/auto_eq/freq_eq_20250820141019.py +77 -0
  40. neverlib/.history/filter/auto_eq/freq_eq_20250820141049.py +77 -0
  41. neverlib/.history/filter/auto_eq/freq_eq_20250820141211.py +77 -0
  42. neverlib/.history/filter/auto_eq/freq_eq_20250820141227.py +77 -0
  43. neverlib/.history/filter/auto_eq/freq_eq_20250820141311.py +78 -0
  44. neverlib/.history/filter/auto_eq/freq_eq_20250820141340.py +78 -0
  45. neverlib/.history/filter/auto_eq/freq_eq_20250820141712.py +78 -0
  46. neverlib/.history/filter/auto_eq/freq_eq_20250820141733.py +78 -0
  47. neverlib/.history/filter/auto_eq/freq_eq_20250820141755.py +78 -0
  48. neverlib/.history/filter/auto_eq/freq_eq_20250821102434.py +76 -0
  49. neverlib/.history/filter/auto_eq/freq_eq_20250821102500.py +76 -0
  50. neverlib/.history/filter/auto_eq/freq_eq_20250821102502.py +76 -0
  51. neverlib/.history/filter/auto_eq/ga_eq_basic_20250820102957.py +380 -0
  52. neverlib/.history/filter/auto_eq/ga_eq_basic_20250820113054.py +380 -0
  53. neverlib/.history/filter/auto_eq/ga_eq_basic_20250820113150.py +380 -0
  54. neverlib/.history/filter/auto_eq/ga_eq_basic_20250820113520.py +385 -0
  55. neverlib/.history/filter/auto_eq/ga_eq_basic_20250820113525.py +385 -0
  56. neverlib/.history/filter/auto_eq/ga_eq_basic_20250821102212.py +385 -0
  57. neverlib/.history/metrics/dnsmos_20250806001612.py +160 -0
  58. neverlib/.history/metrics/dnsmos_20250815180659.py +160 -0
  59. neverlib/.history/metrics/dnsmos_20250815180701.py +158 -0
  60. neverlib/.history/metrics/dnsmos_20250815181321.py +154 -0
  61. neverlib/.history/metrics/dnsmos_20250815181327.py +154 -0
  62. neverlib/.history/metrics/dnsmos_20250815181331.py +154 -0
  63. neverlib/.history/metrics/dnsmos_20250815181620.py +154 -0
  64. neverlib/.history/metrics/dnsmos_20250815181631.py +154 -0
  65. neverlib/.history/metrics/dnsmos_20250815181742.py +154 -0
  66. neverlib/.history/metrics/dnsmos_20250815181824.py +153 -0
  67. neverlib/.history/metrics/dnsmos_20250815181834.py +153 -0
  68. neverlib/.history/metrics/dnsmos_20250815181922.py +153 -0
  69. neverlib/.history/metrics/dnsmos_20250815182011.py +147 -0
  70. neverlib/.history/metrics/dnsmos_20250815182036.py +144 -0
  71. neverlib/.history/metrics/dnsmos_20250815182936.py +143 -0
  72. neverlib/.history/metrics/dnsmos_20250815182942.py +143 -0
  73. neverlib/.history/metrics/dnsmos_20250815183032.py +137 -0
  74. neverlib/.history/metrics/dnsmos_20250815183101.py +144 -0
  75. neverlib/.history/metrics/dnsmos_20250815183121.py +144 -0
  76. neverlib/.history/metrics/dnsmos_20250815183123.py +143 -0
  77. neverlib/.history/metrics/dnsmos_20250815183214.py +143 -0
  78. neverlib/.history/metrics/dnsmos_20250815183240.py +143 -0
  79. neverlib/.history/metrics/dnsmos_20250815183248.py +144 -0
  80. neverlib/.history/metrics/dnsmos_20250815183407.py +142 -0
  81. neverlib/.history/metrics/dnsmos_20250815183409.py +142 -0
  82. neverlib/.history/metrics/dnsmos_20250815183431.py +142 -0
  83. neverlib/.history/metrics/dnsmos_20250815183507.py +140 -0
  84. neverlib/.history/metrics/dnsmos_20250815183513.py +139 -0
  85. neverlib/.history/metrics/dnsmos_20250815183618.py +139 -0
  86. neverlib/.history/metrics/dnsmos_20250815183709.py +140 -0
  87. neverlib/.history/metrics/dnsmos_20250815183756.py +137 -0
  88. neverlib/.history/metrics/dnsmos_20250815183815.py +128 -0
  89. neverlib/.history/metrics/dnsmos_20250815183827.py +129 -0
  90. neverlib/.history/metrics/dnsmos_20250815183913.py +117 -0
  91. neverlib/.history/metrics/dnsmos_20250815183914.py +117 -0
  92. neverlib/.history/metrics/dnsmos_20250815184003.py +118 -0
  93. neverlib/.history/metrics/dnsmos_20250815184040.py +118 -0
  94. neverlib/.history/metrics/dnsmos_20250815184049.py +118 -0
  95. neverlib/.history/metrics/dnsmos_20250815184104.py +117 -0
  96. neverlib/.history/metrics/dnsmos_20250815184200.py +117 -0
  97. neverlib/.history/metrics/lpc_lsp_metric_20250816015944.py +128 -0
  98. neverlib/.history/metrics/lpc_lsp_metric_20250816020142.py +128 -0
  99. neverlib/.history/metrics/lpc_lsp_metric_20250816020156.py +128 -0
  100. neverlib/.history/metrics/lpc_lsp_metric_20250816020554.py +130 -0
  101. neverlib/.history/metrics/lpc_lsp_metric_20250816020600.py +125 -0
  102. neverlib/.history/metrics/lpc_lsp_metric_20250816020631.py +120 -0
  103. neverlib/.history/metrics/lpc_lsp_metric_20250816020746.py +118 -0
  104. neverlib/.history/metrics/lpc_me_20250816013111.py +0 -0
  105. neverlib/.history/metrics/lpc_me_20250816013129.py +121 -0
  106. neverlib/.history/metrics/lpc_me_20250816015430.py +103 -0
  107. neverlib/.history/metrics/lpc_me_20250816015535.py +96 -0
  108. neverlib/.history/metrics/lpc_me_20250816015542.py +96 -0
  109. neverlib/.history/metrics/lpc_me_20250816015636.py +97 -0
  110. neverlib/.history/metrics/lpc_me_20250816015658.py +104 -0
  111. neverlib/.history/metrics/lpc_me_20250816015703.py +100 -0
  112. neverlib/.history/metrics/lpc_me_20250816015945.py +128 -0
  113. neverlib/.history/metrics/snr_20250806010538.py +177 -0
  114. neverlib/.history/metrics/snr_20250806211634.py +184 -0
  115. neverlib/.history/metrics/spec_20250805234209.py +45 -0
  116. neverlib/.history/metrics/spec_20250816135530.py +11 -0
  117. neverlib/.history/metrics/spec_20250816135654.py +16 -0
  118. neverlib/.history/metrics/spec_20250816135736.py +68 -0
  119. neverlib/.history/metrics/spec_20250816135904.py +75 -0
  120. neverlib/.history/metrics/spec_20250816135921.py +82 -0
  121. neverlib/.history/metrics/spec_20250816140111.py +82 -0
  122. neverlib/.history/metrics/spec_20250816140543.py +136 -0
  123. neverlib/.history/metrics/spec_20250816140559.py +172 -0
  124. neverlib/.history/metrics/spec_20250816140602.py +172 -0
  125. neverlib/.history/metrics/spec_20250816140608.py +172 -0
  126. neverlib/.history/metrics/spec_20250816140654.py +148 -0
  127. neverlib/.history/metrics/spec_20250816140705.py +144 -0
  128. neverlib/.history/metrics/spec_20250816140755.py +138 -0
  129. neverlib/.history/metrics/spec_20250816140823.py +170 -0
  130. neverlib/.history/metrics/spec_20250816140832.py +170 -0
  131. neverlib/.history/metrics/spec_20250816140833.py +170 -0
  132. neverlib/.history/metrics/spec_20250816140922.py +147 -0
  133. neverlib/.history/metrics/spec_20250816141148.py +107 -0
  134. neverlib/.history/metrics/spec_20250816141219.py +123 -0
  135. neverlib/.history/metrics/spec_20250816141732.py +178 -0
  136. neverlib/.history/metrics/spec_20250816141740.py +178 -0
  137. neverlib/.history/metrics/spec_20250816142030.py +178 -0
  138. neverlib/.history/metrics/spec_20250816142107.py +135 -0
  139. neverlib/.history/metrics/spec_20250816142126.py +135 -0
  140. neverlib/.history/metrics/spec_20250816142410.py +135 -0
  141. neverlib/.history/metrics/spec_20250816142415.py +136 -0
  142. neverlib/.history/metrics/spec_metric_20250816135156.py +0 -0
  143. neverlib/.history/metrics/spec_metric_20250816135226.py +5 -0
  144. neverlib/.history/metrics/spec_metric_20250816135227.py +10 -0
  145. neverlib/.history/metrics/spec_metric_20250816135306.py +15 -0
  146. neverlib/.history/metrics/spec_metric_20250816135442.py +31 -0
  147. neverlib/.history/metrics/spec_metric_20250816135448.py +31 -0
  148. neverlib/.history/metrics/spec_metric_20250816135520.py +29 -0
  149. neverlib/.history/metrics/spec_metric_20250816135537.py +63 -0
  150. neverlib/.history/metrics/spec_metric_20250816135653.py +65 -0
  151. neverlib/.history/vad/PreProcess_20250805234211.py +63 -0
  152. neverlib/.history/vad/PreProcess_20250809232455.py +63 -0
  153. neverlib/.history/vad/PreProcess_20250816020725.py +66 -0
  154. neverlib/.history/vad/VAD_Silero_20250805234211.py +50 -0
  155. neverlib/.history/vad/VAD_Silero_20250809232456.py +50 -0
  156. neverlib/.history/vad/VAD_WebRTC_20250805234211.py +61 -0
  157. neverlib/.history/vad/VAD_WebRTC_20250809232456.py +61 -0
  158. neverlib/.history/vad/VAD_funasr_20250805234211.py +54 -0
  159. neverlib/.history/vad/VAD_funasr_20250809232456.py +54 -0
  160. neverlib/.history/vad/VAD_vadlib_20250805234211.py +70 -0
  161. neverlib/.history/vad/VAD_vadlib_20250809232455.py +70 -0
  162. neverlib/.history/vad/VAD_whisper_20250805234211.py +55 -0
  163. neverlib/.history/vad/VAD_whisper_20250809232456.py +55 -0
  164. neverlib/.specstory/.what-is-this.md +69 -0
  165. neverlib/.specstory/history/2025-08-05_17-06Z-/350/277/231/344/270/200/346/255/245/347/232/204/347/233/256/347/232/204/346/230/257/344/273/200/344/271/210.md +424 -0
  166. neverlib/Docs/audio_aug/test_snr.py +55 -0
  167. neverlib/__init__.py +2 -2
  168. neverlib/audio_aug/HarmonicDistortion.py +79 -0
  169. neverlib/audio_aug/TFDrop.py +41 -0
  170. neverlib/audio_aug/TFMask.py +56 -0
  171. neverlib/audio_aug/__init__.py +1 -1
  172. neverlib/audio_aug/audio_aug.py +19 -5
  173. neverlib/audio_aug/clip_aug.py +41 -0
  174. neverlib/audio_aug/coder_aug.py +209 -0
  175. neverlib/audio_aug/coder_aug2.py +118 -0
  176. neverlib/audio_aug/loss_packet_aug.py +103 -0
  177. neverlib/audio_aug/quant_aug.py +78 -0
  178. neverlib/data_analyze/README.md +234 -0
  179. neverlib/data_analyze/__init__.py +14 -0
  180. neverlib/data_analyze/dataset_analyzer.py +590 -0
  181. neverlib/data_analyze/quality_metrics.py +364 -0
  182. neverlib/data_analyze/rms_distrubution.py +62 -0
  183. neverlib/data_analyze/spectral_analysis.py +218 -0
  184. neverlib/data_analyze/statistics.py +406 -0
  185. neverlib/data_analyze/temporal_features.py +126 -0
  186. neverlib/data_analyze/visualization.py +468 -0
  187. neverlib/filter/README.md +101 -0
  188. neverlib/filter/__init__.py +7 -0
  189. neverlib/filter/auto_eq/README.md +165 -0
  190. neverlib/filter/auto_eq/__init__.py +36 -0
  191. neverlib/filter/auto_eq/de_eq.py +360 -0
  192. neverlib/filter/auto_eq/freq_eq.py +76 -0
  193. neverlib/filter/auto_eq/ga_eq_advanced.py +577 -0
  194. neverlib/filter/auto_eq/ga_eq_basic.py +385 -0
  195. neverlib/filter/biquad.py +45 -0
  196. neverlib/filter/common.py +5 -6
  197. neverlib/filter/core.py +339 -0
  198. neverlib/metrics/dnsmos.py +117 -0
  199. neverlib/metrics/lpc_lsp.py +118 -0
  200. neverlib/metrics/snr.py +184 -0
  201. neverlib/metrics/spec.py +136 -0
  202. neverlib/metrics/test_pesq.py +35 -0
  203. neverlib/metrics/time.py +68 -0
  204. neverlib/tests/test_vad.py +21 -0
  205. neverlib/utils/audio_split.py +2 -1
  206. neverlib/utils/message.py +4 -4
  207. neverlib/utils/utils.py +36 -16
  208. neverlib/vad/PreProcess.py +6 -3
  209. neverlib/vad/README.md +10 -10
  210. neverlib/vad/VAD_Energy.py +1 -1
  211. neverlib/vad/VAD_Silero.py +2 -2
  212. neverlib/vad/VAD_WebRTC.py +2 -2
  213. neverlib/vad/VAD_funasr.py +2 -2
  214. neverlib/vad/VAD_statistics.py +3 -3
  215. neverlib/vad/VAD_vadlib.py +3 -3
  216. neverlib/vad/VAD_whisper.py +2 -2
  217. neverlib/vad/__init__.py +1 -1
  218. neverlib/vad/class_get_speech.py +4 -4
  219. neverlib/vad/class_vad.py +1 -1
  220. neverlib/vad/utils.py +47 -5
  221. {neverlib-0.2.2.dist-info → neverlib-0.2.4.dist-info}/METADATA +120 -120
  222. neverlib-0.2.4.dist-info/RECORD +229 -0
  223. {neverlib-0.2.2.dist-info → neverlib-0.2.4.dist-info}/WHEEL +1 -1
  224. neverlib/Documents/vad/VAD_Energy.ipynb +0 -159
  225. neverlib/Documents/vad/VAD_Silero.ipynb +0 -305
  226. neverlib/Documents/vad/VAD_WebRTC.ipynb +0 -183
  227. neverlib/Documents/vad/VAD_funasr.ipynb +0 -179
  228. neverlib/Documents/vad/VAD_ppasr.ipynb +0 -175
  229. neverlib/Documents/vad/VAD_statistics.ipynb +0 -522
  230. neverlib/Documents/vad/VAD_vadlib.ipynb +0 -184
  231. neverlib/Documents/vad/VAD_whisper.ipynb +0 -430
  232. neverlib/utils/waveform_analyzer.py +0 -51
  233. neverlib/wav_data/000_short.wav +0 -0
  234. neverlib-0.2.2.dist-info/RECORD +0 -40
  235. {neverlib-0.2.2.dist-info → neverlib-0.2.4.dist-info}/licenses/LICENSE +0 -0
  236. {neverlib-0.2.2.dist-info → neverlib-0.2.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,468 @@
1
+ """
2
+ 可视化模块
3
+ Visualization Module
4
+
5
+ 提供音频数据可视化功能
6
+ """
7
+
8
+ import numpy as np
9
+ import librosa
10
+ import matplotlib.pyplot as plt
11
+ import matplotlib.patches as patches
12
+ from matplotlib.colors import LinearSegmentedColormap
13
+ import seaborn as sns
14
+ from typing import List, Dict, Tuple, Optional, Union
15
+ import warnings
16
+ from scipy.signal import spectrogram
17
+
18
+
19
+ class AudioVisualizer:
20
+ """音频可视化器类"""
21
+
22
+ def __init__(self, sr: int = 22050, figsize: Tuple[int, int] = (12, 8)):
23
+ """
24
+ 初始化可视化器
25
+
26
+ Args:
27
+ sr: 采样率
28
+ figsize: 图形大小
29
+ """
30
+ self.sr = sr
31
+ self.figsize = figsize
32
+
33
+ # 设置中文字体支持
34
+ plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
35
+ plt.rcParams['axes.unicode_minus'] = False
36
+
37
+ # 设置样式
38
+ plt.style.use('default')
39
+ sns.set_palette("husl")
40
+
41
+ def plot_waveform(self, audio: np.ndarray, title: str = "音频波形图",
42
+ show_time: bool = True, ax: Optional[plt.Axes] = None) -> plt.Figure:
43
+ """
44
+ 绘制音频波形图
45
+
46
+ Args:
47
+ audio: 音频信号
48
+ title: 图标题
49
+ show_time: 是否显示时间轴
50
+ ax: matplotlib轴对象
51
+
52
+ Returns:
53
+ 图形对象
54
+ """
55
+ if ax is None:
56
+ fig, ax = plt.subplots(figsize=self.figsize)
57
+ else:
58
+ fig = ax.figure
59
+
60
+ if show_time:
61
+ time_axis = np.linspace(0, len(audio) / self.sr, len(audio))
62
+ ax.plot(time_axis, audio, linewidth=0.5, alpha=0.8)
63
+ ax.set_xlabel('时间 (s)')
64
+ else:
65
+ ax.plot(audio, linewidth=0.5, alpha=0.8)
66
+ ax.set_xlabel('样本点')
67
+
68
+ ax.set_ylabel('幅度')
69
+ ax.set_title(title)
70
+ ax.grid(True, alpha=0.3)
71
+
72
+ # 添加零线
73
+ ax.axhline(y=0, color='red', linestyle='--', alpha=0.5)
74
+
75
+ plt.tight_layout()
76
+ return fig
77
+
78
+ def plot_spectrogram(self, audio: np.ndarray, title: str = "频谱图",
79
+ n_fft: int = 2048, hop_length: int = 512,
80
+ ax: Optional[plt.Axes] = None) -> plt.Figure:
81
+ """
82
+ 绘制频谱图
83
+
84
+ Args:
85
+ audio: 音频信号
86
+ title: 图标题
87
+ n_fft: FFT窗口大小
88
+ hop_length: 跳跃长度
89
+ ax: matplotlib轴对象
90
+
91
+ Returns:
92
+ 图形对象
93
+ """
94
+ if ax is None:
95
+ fig, ax = plt.subplots(figsize=self.figsize)
96
+ else:
97
+ fig = ax.figure
98
+
99
+ # 计算频谱图
100
+ D = librosa.stft(audio, n_fft=n_fft, hop_length=hop_length)
101
+ S_db = librosa.amplitude_to_db(np.abs(D), ref=np.max)
102
+
103
+ # 绘制
104
+ img = librosa.display.specshow(S_db, sr=self.sr, hop_length=hop_length,
105
+ x_axis='time', y_axis='hz', ax=ax)
106
+
107
+ ax.set_title(title)
108
+ ax.set_xlabel('时间 (s)')
109
+ ax.set_ylabel('频率 (Hz)')
110
+
111
+ # 添加颜色条
112
+ cbar = plt.colorbar(img, ax=ax, format='%+2.0f dB')
113
+ cbar.set_label('幅度 (dB)')
114
+
115
+ plt.tight_layout()
116
+ return fig
117
+
118
+ def plot_mel_spectrogram(self, audio: np.ndarray, title: str = "梅尔频谱图",
119
+ n_mels: int = 128, ax: Optional[plt.Axes] = None) -> plt.Figure:
120
+ """
121
+ 绘制梅尔频谱图
122
+
123
+ Args:
124
+ audio: 音频信号
125
+ title: 图标题
126
+ n_mels: 梅尔滤波器数量
127
+ ax: matplotlib轴对象
128
+
129
+ Returns:
130
+ 图形对象
131
+ """
132
+ if ax is None:
133
+ fig, ax = plt.subplots(figsize=self.figsize)
134
+ else:
135
+ fig = ax.figure
136
+
137
+ # 计算梅尔频谱图
138
+ S = librosa.feature.melspectrogram(y=audio, sr=self.sr, n_mels=n_mels)
139
+ S_db = librosa.power_to_db(S, ref=np.max)
140
+
141
+ # 绘制
142
+ img = librosa.display.specshow(S_db, sr=self.sr, x_axis='time',
143
+ y_axis='mel', ax=ax)
144
+
145
+ ax.set_title(title)
146
+ ax.set_xlabel('时间 (s)')
147
+ ax.set_ylabel('梅尔频率')
148
+
149
+ # 添加颜色条
150
+ cbar = plt.colorbar(img, ax=ax, format='%+2.0f dB')
151
+ cbar.set_label('功率 (dB)')
152
+
153
+ plt.tight_layout()
154
+ return fig
155
+
156
+ def plot_spectrum(self, audio: np.ndarray, title: str = "频谱",
157
+ log_scale: bool = True, ax: Optional[plt.Axes] = None) -> plt.Figure:
158
+ """
159
+ 绘制频谱
160
+
161
+ Args:
162
+ audio: 音频信号
163
+ title: 图标题
164
+ log_scale: 是否使用对数刻度
165
+ ax: matplotlib轴对象
166
+
167
+ Returns:
168
+ 图形对象
169
+ """
170
+ if ax is None:
171
+ fig, ax = plt.subplots(figsize=self.figsize)
172
+ else:
173
+ fig = ax.figure
174
+
175
+ # 计算FFT
176
+ fft_data = np.fft.fft(audio)
177
+ magnitude = np.abs(fft_data)
178
+ freqs = np.fft.fftfreq(len(audio), 1/self.sr)
179
+
180
+ # 只取正频率部分
181
+ positive_idx = freqs >= 0
182
+ freqs = freqs[positive_idx]
183
+ magnitude = magnitude[positive_idx]
184
+
185
+ if log_scale:
186
+ magnitude_db = 20 * np.log10(magnitude + 1e-10)
187
+ ax.plot(freqs, magnitude_db)
188
+ ax.set_ylabel('幅度 (dB)')
189
+ else:
190
+ ax.plot(freqs, magnitude)
191
+ ax.set_ylabel('幅度')
192
+
193
+ ax.set_xlabel('频率 (Hz)')
194
+ ax.set_title(title)
195
+ ax.grid(True, alpha=0.3)
196
+
197
+ plt.tight_layout()
198
+ return fig
199
+
200
+ def plot_features_comparison(self, features_dict: Dict[str, np.ndarray],
201
+ title: str = "特征对比") -> plt.Figure:
202
+ """
203
+ 绘制多个特征的对比图
204
+
205
+ Args:
206
+ features_dict: 特征字典 {特征名: 特征值数组}
207
+ title: 图标题
208
+
209
+ Returns:
210
+ 图形对象
211
+ """
212
+ n_features = len(features_dict)
213
+ fig, axes = plt.subplots(n_features, 1, figsize=(self.figsize[0], self.figsize[1] * n_features / 2))
214
+
215
+ if n_features == 1:
216
+ axes = [axes]
217
+
218
+ for i, (feature_name, feature_values) in enumerate(features_dict.items()):
219
+ if len(feature_values.shape) == 1:
220
+ # 一维特征
221
+ time_axis = np.linspace(0, len(feature_values) / (self.sr / 512), len(feature_values))
222
+ axes[i].plot(time_axis, feature_values)
223
+ axes[i].set_ylabel(feature_name)
224
+ else:
225
+ # 二维特征(如MFCC)
226
+ img = axes[i].imshow(feature_values, aspect='auto', origin='lower')
227
+ axes[i].set_ylabel(feature_name)
228
+ plt.colorbar(img, ax=axes[i])
229
+
230
+ axes[i].set_title(f'{feature_name} 特征')
231
+ axes[i].grid(True, alpha=0.3)
232
+
233
+ axes[-1].set_xlabel('时间 (s)')
234
+ plt.suptitle(title)
235
+ plt.tight_layout()
236
+ return fig
237
+
238
+ def plot_statistics_distribution(self, stats_dict: Dict[str, List[float]],
239
+ title: str = "统计分布图") -> plt.Figure:
240
+ """
241
+ 绘制统计分布图
242
+
243
+ Args:
244
+ stats_dict: 统计数据字典
245
+ title: 图标题
246
+
247
+ Returns:
248
+ 图形对象
249
+ """
250
+ n_stats = len(stats_dict)
251
+ fig, axes = plt.subplots(2, (n_stats + 1) // 2, figsize=(self.figsize[0], self.figsize[1]))
252
+
253
+ if n_stats == 1:
254
+ axes = [axes]
255
+ elif n_stats == 2:
256
+ axes = axes.flatten()
257
+ else:
258
+ axes = axes.flatten()
259
+
260
+ for i, (stat_name, values) in enumerate(stats_dict.items()):
261
+ if i >= len(axes):
262
+ break
263
+
264
+ # 绘制直方图和KDE
265
+ axes[i].hist(values, bins=30, alpha=0.7, density=True, color='skyblue')
266
+
267
+ try:
268
+ sns.kdeplot(values, ax=axes[i], color='red')
269
+ except:
270
+ pass
271
+
272
+ axes[i].set_title(f'{stat_name} 分布')
273
+ axes[i].set_xlabel(stat_name)
274
+ axes[i].set_ylabel('密度')
275
+ axes[i].grid(True, alpha=0.3)
276
+
277
+ # 隐藏未使用的子图
278
+ for j in range(i + 1, len(axes)):
279
+ axes[j].set_visible(False)
280
+
281
+ plt.suptitle(title)
282
+ plt.tight_layout()
283
+ return fig
284
+
285
+ def plot_rms_distribution(self, rms_values: List[float],
286
+ title: str = "RMS分布图") -> plt.Figure:
287
+ """
288
+ 绘制RMS分布图
289
+
290
+ Args:
291
+ rms_values: RMS值列表
292
+ title: 图标题
293
+
294
+ Returns:
295
+ 图形对象
296
+ """
297
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=self.figsize)
298
+
299
+ # 线性尺度分布
300
+ ax1.hist(rms_values, bins=50, alpha=0.7, color='lightblue', edgecolor='black')
301
+ ax1.set_xlabel('RMS 幅度')
302
+ ax1.set_ylabel('频次')
303
+ ax1.set_title('RMS 线性分布')
304
+ ax1.grid(True, alpha=0.3)
305
+
306
+ # 对数尺度分布
307
+ rms_db = [20 * np.log10(rms + 1e-10) for rms in rms_values]
308
+ ax2.hist(rms_db, bins=50, alpha=0.7, color='lightgreen', edgecolor='black')
309
+ ax2.set_xlabel('RMS (dB)')
310
+ ax2.set_ylabel('频次')
311
+ ax2.set_title('RMS 对数分布')
312
+ ax2.grid(True, alpha=0.3)
313
+
314
+ plt.suptitle(title)
315
+ plt.tight_layout()
316
+ return fig
317
+
318
+ def plot_audio_comparison(self, audio1: np.ndarray, audio2: np.ndarray,
319
+ labels: List[str] = None, title: str = "音频对比") -> plt.Figure:
320
+ """
321
+ 绘制两个音频的对比图
322
+
323
+ Args:
324
+ audio1: 第一个音频
325
+ audio2: 第二个音频
326
+ labels: 标签列表
327
+ title: 图标题
328
+
329
+ Returns:
330
+ 图形对象
331
+ """
332
+ if labels is None:
333
+ labels = ['音频1', '音频2']
334
+
335
+ fig, axes = plt.subplots(3, 2, figsize=(self.figsize[0], self.figsize[1] * 1.5))
336
+
337
+ # 时域波形对比
338
+ time1 = np.linspace(0, len(audio1) / self.sr, len(audio1))
339
+ time2 = np.linspace(0, len(audio2) / self.sr, len(audio2))
340
+
341
+ axes[0, 0].plot(time1, audio1, alpha=0.8)
342
+ axes[0, 0].set_title(f'{labels[0]} - 波形')
343
+ axes[0, 0].set_xlabel('时间 (s)')
344
+ axes[0, 0].set_ylabel('幅度')
345
+ axes[0, 0].grid(True, alpha=0.3)
346
+
347
+ axes[0, 1].plot(time2, audio2, alpha=0.8, color='orange')
348
+ axes[0, 1].set_title(f'{labels[1]} - 波形')
349
+ axes[0, 1].set_xlabel('时间 (s)')
350
+ axes[0, 1].set_ylabel('幅度')
351
+ axes[0, 1].grid(True, alpha=0.3)
352
+
353
+ # 频谱对比
354
+ self.plot_spectrum(audio1, f'{labels[0]} - 频谱', ax=axes[1, 0])
355
+ self.plot_spectrum(audio2, f'{labels[1]} - 频谱', ax=axes[1, 1])
356
+
357
+ # 频谱图对比
358
+ self.plot_spectrogram(audio1, f'{labels[0]} - 频谱图', ax=axes[2, 0])
359
+ self.plot_spectrogram(audio2, f'{labels[1]} - 频谱图', ax=axes[2, 1])
360
+
361
+ plt.suptitle(title)
362
+ plt.tight_layout()
363
+ return fig
364
+
365
+
366
+ def plot_dataset_overview(file_paths: List[str], max_files: int = 10,
367
+ sr: int = 22050) -> plt.Figure:
368
+ """
369
+ 绘制数据集概览
370
+
371
+ Args:
372
+ file_paths: 音频文件路径列表
373
+ max_files: 最大显示文件数
374
+ sr: 采样率
375
+
376
+ Returns:
377
+ 图形对象
378
+ """
379
+ visualizer = AudioVisualizer(sr=sr)
380
+
381
+ # 限制文件数量
382
+ selected_files = file_paths[:max_files]
383
+
384
+ fig, axes = plt.subplots(len(selected_files), 2,
385
+ figsize=(15, 3 * len(selected_files)))
386
+
387
+ if len(selected_files) == 1:
388
+ axes = axes.reshape(1, -1)
389
+
390
+ for i, file_path in enumerate(selected_files):
391
+ try:
392
+ audio, _ = librosa.load(file_path, sr=sr)
393
+
394
+ # 波形图
395
+ visualizer.plot_waveform(audio, f'文件 {i+1}: 波形', ax=axes[i, 0])
396
+
397
+ # 频谱图
398
+ visualizer.plot_spectrogram(audio, f'文件 {i+1}: 频谱图', ax=axes[i, 1])
399
+
400
+ except Exception as e:
401
+ axes[i, 0].text(0.5, 0.5, f'加载失败: {str(e)}',
402
+ ha='center', va='center', transform=axes[i, 0].transAxes)
403
+ axes[i, 1].text(0.5, 0.5, f'加载失败: {str(e)}',
404
+ ha='center', va='center', transform=axes[i, 1].transAxes)
405
+
406
+ plt.suptitle('数据集概览')
407
+ plt.tight_layout()
408
+ return fig
409
+
410
+
411
+ def create_analysis_dashboard(audio: np.ndarray, sr: int = 22050) -> plt.Figure:
412
+ """
413
+ 创建音频分析仪表板
414
+
415
+ Args:
416
+ audio: 音频信号
417
+ sr: 采样率
418
+
419
+ Returns:
420
+ 仪表板图形对象
421
+ """
422
+ visualizer = AudioVisualizer(sr=sr)
423
+
424
+ fig = plt.figure(figsize=(16, 12))
425
+
426
+ # 创建网格布局
427
+ gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)
428
+
429
+ # 时域波形
430
+ ax1 = fig.add_subplot(gs[0, :])
431
+ visualizer.plot_waveform(audio, "时域波形", ax=ax1)
432
+
433
+ # 频谱图
434
+ ax2 = fig.add_subplot(gs[1, :2])
435
+ visualizer.plot_spectrogram(audio, "频谱图", ax=ax2)
436
+
437
+ # 频谱
438
+ ax3 = fig.add_subplot(gs[1, 2])
439
+ visualizer.plot_spectrum(audio, "频谱", ax=ax3)
440
+
441
+ # 梅尔频谱图
442
+ ax4 = fig.add_subplot(gs[2, :2])
443
+ visualizer.plot_mel_spectrogram(audio, "梅尔频谱图", ax=ax4)
444
+
445
+ # 特征统计
446
+ ax5 = fig.add_subplot(gs[2, 2])
447
+
448
+ # 计算基本统计
449
+ duration = len(audio) / sr
450
+ max_amp = np.max(np.abs(audio))
451
+ rms_amp = np.sqrt(np.mean(audio ** 2))
452
+
453
+ stats_text = f"""音频统计信息:
454
+ 时长: {duration:.2f}s
455
+ 最大幅度: {max_amp:.4f}
456
+ RMS: {rms_amp:.4f}
457
+ RMS (dB): {20*np.log10(rms_amp):.2f}
458
+ 采样率: {sr} Hz
459
+ 样本数: {len(audio)}
460
+ """
461
+
462
+ ax5.text(0.1, 0.5, stats_text, transform=ax5.transAxes,
463
+ fontsize=10, verticalalignment='center')
464
+ ax5.set_title("统计信息")
465
+ ax5.axis('off')
466
+
467
+ plt.suptitle("音频分析仪表板", fontsize=16)
468
+ return fig
@@ -0,0 +1,101 @@
1
+ # neverlib.filter
2
+
3
+ 本项目包含音频滤波器的实现和自动EQ匹配算法, 主要基于 scipy.signal 进行封装和扩展, 提供便捷的音频滤波器设计、处理功能以及智能EQ补偿解决方案。
4
+
5
+ ## 主要功能
6
+
7
+ ### 滤波器类型
8
+ - 低通滤波器 (Low Pass Filter, LPF)
9
+ - 高通滤波器 (High Pass Filter, HPF)
10
+ - 带通滤波器 (Band Pass Filter, BPF)
11
+ - 恒定裙边增益模式 (constant skirt gain, peak gain = Q)
12
+ - 恒定 0dB 峰值增益模式 (constant 0 dB peak gain)
13
+ - 陷波滤波器 (Notch Filter)
14
+ - 全通滤波器 (All Pass Filter, APF)
15
+ - 峰值滤波器 (Peaking EQ)
16
+ - 低切滤波器 (Low Shelf Filter)
17
+ - 高切滤波器 (High Shelf Filter)
18
+
19
+ ### 核心文件说明
20
+ - `filters.py`: 提供 EQFilter 类, 包含多种滤波器的设计和实现
21
+ - `biquad.py`: 二阶节(Biquad)滤波器的实现, 支持逐点处理
22
+ - `common.py`: 基础滤波器函数, 提供 numpy/scipy 和 torch 版本
23
+
24
+ ### 自动EQ匹配算法 (AudoEQ/)
25
+ 提供多种智能EQ匹配算法, 可以自动分析两个音频文件的频谱差异并生成最优的EQ补偿参数:
26
+
27
+ #### 🧬 基于优化算法的EQ匹配
28
+ - `auto_eq_ga_basic.py`: **基础遗传算法** - 使用DEAP库实现, 代码简洁, 适合学习和快速原型
29
+ - `auto_eq_ga_advanced.py`: **高级遗传算法** - 面向对象设计, 包含日志、检查点、早停等生产级功能
30
+ - `auto_eq_de.py`: **差分进化算法** - 使用scipy优化, 全局收敛性好, 适合高精度匹配
31
+
32
+ #### 📊 基于频谱分析的EQ匹配
33
+ - `auto_eq_spectral_direct.py`: **频谱直接补偿** - 基于STFT频谱分析, 直接计算频谱差异, 速度最快
34
+
35
+ 详细使用说明请参考 `AudoEQ/README.md`
36
+
37
+ ## 使用说明
38
+
39
+ 对于基础滤波需求, 推荐直接使用 scipy.signal 的原生函数:
40
+ ```python
41
+ from scipy import signal
42
+
43
+ # 设计巴特沃斯滤波器
44
+ b, a = signal.butter(N=2, Wn=100, btype='high', fs=16000)
45
+ # 应用滤波器
46
+ filtered = signal.lfilter(b, a, audio)
47
+ ```
48
+
49
+ 对于需要批量处理或自定义参数的场景, 可以使用本库的封装:
50
+ ```python
51
+ from neverlib.filter import EQFilter, BiquadFilter
52
+
53
+ # 使用 EQFilter
54
+ eq = EQFilter(fs=16000)
55
+ b, a = eq.LowpassFilter(fc=300, Q=0.707)
56
+
57
+ # 使用 BiquadFilter 进行逐点处理
58
+ biquad = BiquadFilter(b, a)
59
+ output = [biquad.process(x) for x in input_signal]
60
+ ```
61
+
62
+ ### 自动EQ匹配快速开始
63
+
64
+ 对于需要自动EQ匹配的场景, 可以直接运行AudoEQ中的脚本:
65
+
66
+ ```bash
67
+ # 快速频谱匹配(推荐入门)
68
+ cd AudoEQ
69
+ python auto_eq_spectral_direct.py
70
+
71
+ # 高精度优化匹配
72
+ python auto_eq_de.py # 差分进化算法
73
+ python auto_eq_ga_basic.py # 基础遗传算法
74
+ python auto_eq_ga_advanced.py # 高级遗传算法
75
+ ```
76
+
77
+ 使用前请修改脚本中的音频文件路径:
78
+ ```python
79
+ SOURCE_AUDIO_PATH = "path/to/source.wav" # 源音频
80
+ TARGET_AUDIO_PATH = "path/to/target.wav" # 目标音频
81
+ OUTPUT_MATCHED_AUDIO_PATH = "path/to/output.wav" # 输出音频
82
+ ```
83
+
84
+ ## 详细教程
85
+
86
+ ### 滤波器教程
87
+ 请参考 Documents/filter/ 目录下的 Jupyter notebooks:
88
+ - `filter_family.ipynb`: 各类滤波器的设计和频率响应示例
89
+ - `biquad.ipynb`: 二阶节滤波器的实现和验证
90
+ - `scipy_filter_family.ipynb`: scipy 原生滤波器的使用示例
91
+
92
+ ### 自动EQ匹配教程
93
+ 请参考 `AudoEQ/README.md` 了解:
94
+ - 各种EQ匹配算法的详细介绍和对比
95
+ - 参数调优指南和性能优化建议
96
+ - 常见问题解决方案和故障排除
97
+
98
+ ## 参考资料
99
+ - [Audio-EQ-Cookbook](http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt)
100
+ - [beqdesigner](https://github.com/3ll3d00d/beqdesigner)
101
+ - [torch-audiomentations](https://github.com/iver56/torch-audiomentations)
@@ -1,3 +1,8 @@
1
+ '''
2
+ Author: 凌逆战 | Never
3
+ Date: 2025-03-17 19:23:33
4
+ Description:
5
+ '''
1
6
  """
2
7
  节省路径
3
8
  from neverlib.filter import common
@@ -5,3 +10,5 @@ from neverlib.filter import common
5
10
  from neverlib.filter.common import *
6
11
  """
7
12
  from .common import *
13
+ from .core import *
14
+ from .biquad import *