neverlib 0.2.4__py3-none-any.whl → 0.2.6__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 (260) hide show
  1. neverlib/.history/Docs/audio_aug/del_20250827162530.py +0 -0
  2. neverlib/.history/Docs/audio_aug/del_20250827162540.py +2 -0
  3. neverlib/.history/Docs/audio_aug/del_20250827162541.py +7 -0
  4. neverlib/.history/Docs/audio_aug/del_20250827162606.py +7 -0
  5. neverlib/.history/Docs/audio_aug/del_20250827162637.py +8 -0
  6. neverlib/.history/Docs/audio_aug/del_20250827162645.py +8 -0
  7. neverlib/.history/Docs/audio_aug/del_20250827162723.py +9 -0
  8. neverlib/.history/Docs/audio_aug/del_20250827162739.py +9 -0
  9. neverlib/.history/Docs/audio_aug/test_snr_20250827161751.py +55 -0
  10. neverlib/.history/Docs/audio_aug/test_snr_20250827161754.py +55 -0
  11. neverlib/.history/Docs/audio_aug/test_snr_20250827161833.py +54 -0
  12. neverlib/.history/Docs/audio_aug/test_snr_20250827162017.py +56 -0
  13. neverlib/.history/Docs/audio_aug/test_snr_20250827162021.py +57 -0
  14. neverlib/.history/Docs/audio_aug/test_snr_20250827162028.py +57 -0
  15. neverlib/.history/Docs/audio_aug_test/del_20250827162738.py +9 -0
  16. neverlib/.history/Docs/audio_aug_test/del_20250827162819.py +9 -0
  17. neverlib/.history/Docs/audio_aug_test/del_20250827162830.py +9 -0
  18. neverlib/.history/Docs/audio_aug_test/del_20250827162846.py +9 -0
  19. neverlib/.history/Docs/audio_aug_test/del_20250827162851.py +9 -0
  20. neverlib/.history/Docs/audio_aug_test/del_20250827162903.py +10 -0
  21. neverlib/.history/Docs/audio_aug_test/del_20250827162921.py +10 -0
  22. neverlib/.history/Docs/audio_aug_test/del_20250827162926.py +10 -0
  23. neverlib/.history/Docs/audio_aug_test/del_20250827163030.py +10 -0
  24. neverlib/.history/Docs/audio_aug_test/del_20250827163032.py +10 -0
  25. neverlib/.history/QA/html2markdown_20250822234112.md +0 -0
  26. neverlib/.history/QA/html2markdown_20250822234140.py +9 -0
  27. neverlib/.history/QA/html2markdown_20250822234141.md +9 -0
  28. neverlib/.history/QA/html2markdown_20250822234159.py +12 -0
  29. neverlib/.history/QA/html2markdown_20250822234200.py +17 -0
  30. neverlib/.history/QA/html2markdown_20250822234236.py +17 -0
  31. neverlib/.history/QA/html2markdown_20250822234340.py +14 -0
  32. neverlib/.history/QA/html2markdown_20250822234522.py +18 -0
  33. neverlib/.history/QA/html2markdown_20250822234601.py +20 -0
  34. neverlib/.history/QA/html2markdown_20250822234615.py +22 -0
  35. neverlib/.history/QA/html2markdown_20250822234715.py +28 -0
  36. neverlib/.history/QA/html2markdown_20250822234720.py +27 -0
  37. neverlib/.history/QA/html2markdown_20250822234903.py +27 -0
  38. neverlib/.history/__init___20250805234212.py +41 -0
  39. neverlib/.history/__init___20250904102635.py +39 -0
  40. neverlib/.history/__init___20250904102836.py +34 -0
  41. neverlib/.history/__init___20250904102838.py +39 -0
  42. neverlib/.history/__init___20250904102851.py +33 -0
  43. neverlib/.history/audio_aug/audio_aug_20250826155913.py +158 -0
  44. neverlib/.history/audio_aug/audio_aug_20250826164159.py +159 -0
  45. neverlib/.history/audio_aug/audio_aug_20250826164217.py +160 -0
  46. neverlib/.history/audio_aug/audio_aug_20250826164408.py +161 -0
  47. neverlib/.history/audio_aug/audio_aug_20250826164423.py +161 -0
  48. neverlib/.history/audio_aug/audio_aug_20250826164529.py +161 -0
  49. neverlib/.history/audio_aug/audio_aug_20250826164824.py +161 -0
  50. neverlib/.history/audio_aug/audio_aug_20250826164932.py +162 -0
  51. neverlib/.history/audio_aug/audio_aug_20250826164947.py +162 -0
  52. neverlib/.history/audio_aug/audio_aug_20250826165403.py +162 -0
  53. neverlib/.history/audio_aug/audio_aug_20250826165421.py +162 -0
  54. neverlib/.history/audio_aug/audio_aug_20250826165509.py +163 -0
  55. neverlib/.history/audio_aug/audio_aug_20250826165702.py +163 -0
  56. neverlib/.history/audio_aug/audio_aug_20250826165732.py +165 -0
  57. neverlib/.history/audio_aug/audio_aug_20250826170041.py +163 -0
  58. neverlib/.history/audio_aug/audio_aug_20250826170105.py +164 -0
  59. neverlib/.history/audio_aug/audio_aug_20250826170154.py +164 -0
  60. neverlib/.history/audio_aug/audio_aug_20250826170220.py +165 -0
  61. neverlib/.history/audio_aug/audio_aug_20250826170221.py +165 -0
  62. neverlib/.history/audio_aug/audio_aug_20250826170228.py +165 -0
  63. neverlib/.history/audio_aug/audio_aug_20250826170231.py +165 -0
  64. neverlib/.history/audio_aug/audio_aug_20250826212001.py +165 -0
  65. neverlib/.history/audio_aug/audio_aug_20250826220038.py +165 -0
  66. neverlib/.history/audio_aug/audio_aug_20250826220133.py +165 -0
  67. neverlib/.history/audio_aug/audio_aug_20250826220148.py +165 -0
  68. neverlib/.history/audio_aug/audio_aug_20250826220154.py +165 -0
  69. neverlib/.history/audio_aug/audio_aug_20250826220156.py +165 -0
  70. neverlib/.history/audio_aug/audio_aug_20250826220314.py +165 -0
  71. neverlib/.history/audio_aug/audio_aug_20250826220343.py +184 -0
  72. neverlib/.history/audio_aug/audio_aug_20250826220345.py +184 -0
  73. neverlib/.history/audio_aug/audio_aug_20250826220349.py +184 -0
  74. neverlib/.history/audio_aug/audio_aug_20250826220429.py +184 -0
  75. neverlib/.history/audio_aug/audio_aug_20250826220447.py +184 -0
  76. neverlib/.history/audio_aug/audio_aug_20250826220601.py +186 -0
  77. neverlib/.history/audio_aug/audio_aug_20250826220638.py +186 -0
  78. neverlib/.history/audio_aug/audio_aug_20250826220641.py +186 -0
  79. neverlib/.history/audio_aug/audio_aug_20250826220647.py +186 -0
  80. neverlib/.history/audio_aug/audio_aug_20250826220653.py +186 -0
  81. neverlib/.history/audio_aug/audio_aug_20250826220655.py +186 -0
  82. neverlib/.history/audio_aug/audio_aug_20250826220731.py +185 -0
  83. neverlib/.history/audio_aug/audio_aug_20250826220739.py +185 -0
  84. neverlib/.history/audio_aug/audio_aug_20250826220747.py +185 -0
  85. neverlib/.history/audio_aug/audio_aug_20250826220801.py +186 -0
  86. neverlib/.history/audio_aug/audio_aug_20250826220822.py +186 -0
  87. neverlib/.history/audio_aug/audio_aug_20250826220901.py +186 -0
  88. neverlib/.history/audio_aug/audio_aug_20250826221107.py +187 -0
  89. neverlib/.history/audio_aug/audio_aug_20250826221310.py +188 -0
  90. neverlib/.history/audio_aug/audio_aug_20250826221353.py +191 -0
  91. neverlib/.history/audio_aug/audio_aug_20250826221821.py +191 -0
  92. neverlib/.history/audio_aug/audio_aug_20250826221838.py +191 -0
  93. neverlib/.history/audio_aug/audio_aug_20250826221906.py +191 -0
  94. neverlib/.history/audio_aug/audio_aug_20250826221930.py +191 -0
  95. neverlib/.history/audio_aug/audio_aug_20250826221939.py +191 -0
  96. neverlib/.history/audio_aug/audio_aug_20250826221955.py +191 -0
  97. neverlib/.history/audio_aug/audio_aug_20250826222008.py +197 -0
  98. neverlib/.history/audio_aug/audio_aug_20250826222017.py +200 -0
  99. neverlib/.history/audio_aug/audio_aug_20250826222046.py +203 -0
  100. neverlib/.history/audio_aug/audio_aug_20250826222105.py +203 -0
  101. neverlib/.history/audio_aug/audio_aug_20250826222206.py +203 -0
  102. neverlib/.history/audio_aug/audio_aug_20250826222302.py +203 -0
  103. neverlib/.history/audio_aug/audio_aug_20250826222336.py +203 -0
  104. neverlib/.history/audio_aug/audio_aug_20250826222455.py +204 -0
  105. neverlib/.history/audio_aug/audio_aug_20250826222526.py +204 -0
  106. neverlib/.history/audio_aug/audio_aug_20250826222541.py +204 -0
  107. neverlib/.history/audio_aug/audio_aug_20250826222624.py +202 -0
  108. neverlib/.history/audio_aug/audio_aug_20250826222714.py +205 -0
  109. neverlib/.history/audio_aug/audio_aug_20250826222820.py +205 -0
  110. neverlib/.history/audio_aug/audio_aug_20250826222827.py +205 -0
  111. neverlib/.history/audio_aug/audio_aug_20250826222927.py +232 -0
  112. neverlib/.history/audio_aug/audio_aug_20250826223009.py +232 -0
  113. neverlib/.history/audio_aug/audio_aug_20250826223054.py +232 -0
  114. neverlib/.history/audio_aug/audio_aug_20250826223225.py +233 -0
  115. neverlib/.history/audio_aug/audio_aug_20250826223344.py +236 -0
  116. neverlib/.history/audio_aug/audio_aug_20250826223356.py +236 -0
  117. neverlib/.history/audio_aug/audio_aug_20250826223955.py +242 -0
  118. neverlib/.history/audio_aug/audio_aug_20250826224210.py +240 -0
  119. neverlib/.history/audio_aug/audio_aug_20250826224250.py +242 -0
  120. neverlib/.history/audio_aug/audio_aug_20250826224323.py +280 -0
  121. neverlib/.history/audio_aug/audio_aug_20250826224452.py +263 -0
  122. neverlib/.history/audio_aug/audio_aug_20250826224455.py +263 -0
  123. neverlib/.history/audio_aug/audio_aug_20250826224502.py +263 -0
  124. neverlib/.history/audio_aug/audio_aug_20250826224528.py +263 -0
  125. neverlib/.history/audio_aug/audio_aug_20250826224658.py +263 -0
  126. neverlib/.history/audio_aug/audio_aug_20250826224833.py +264 -0
  127. neverlib/.history/audio_aug/audio_aug_20250826225013.py +269 -0
  128. neverlib/.history/audio_aug/audio_aug_20250826225050.py +269 -0
  129. neverlib/.history/audio_aug/audio_aug_20250826225241.py +268 -0
  130. neverlib/.history/audio_aug/audio_aug_20250826225315.py +266 -0
  131. neverlib/.history/audio_aug/audio_aug_20250826225404.py +266 -0
  132. neverlib/.history/audio_aug/audio_aug_20250826225502.py +265 -0
  133. neverlib/.history/audio_aug/audio_aug_20250826225950.py +267 -0
  134. neverlib/.history/audio_aug/audio_aug_20250826225959.py +268 -0
  135. neverlib/.history/audio_aug/audio_aug_20250826230222.py +271 -0
  136. neverlib/.history/audio_aug/audio_aug_20250826230248.py +270 -0
  137. neverlib/.history/audio_aug/audio_aug_20250826230638.py +266 -0
  138. neverlib/.history/audio_aug/audio_aug_20250826230755.py +266 -0
  139. neverlib/.history/audio_aug/audio_aug_20250826230941.py +265 -0
  140. neverlib/.history/audio_aug/audio_aug_20250826231054.py +266 -0
  141. neverlib/.history/audio_aug/audio_aug_20250826231117.py +266 -0
  142. neverlib/.history/audio_aug/audio_aug_20250826231219.py +266 -0
  143. neverlib/.history/audio_aug/audio_aug_20250826232330.py +266 -0
  144. neverlib/.history/audio_aug/audio_aug_20250826232352.py +266 -0
  145. neverlib/.history/audio_aug/audio_aug_20250827152748.py +268 -0
  146. neverlib/.history/audio_aug/audio_aug_20250827152806.py +268 -0
  147. neverlib/.history/audio_aug/audio_aug_20250827152808.py +268 -0
  148. neverlib/.history/audio_aug/audio_aug_20250827152917.py +283 -0
  149. neverlib/.history/audio_aug/audio_aug_20250827152929.py +281 -0
  150. neverlib/.history/audio_aug/audio_aug_20250827153100.py +286 -0
  151. neverlib/.history/audio_aug/audio_aug_20250827153102.py +286 -0
  152. neverlib/.history/audio_aug/audio_aug_20250827153301.py +295 -0
  153. neverlib/.history/audio_aug/audio_aug_20250827153331.py +298 -0
  154. neverlib/.history/audio_aug/audio_aug_20250827153525.py +303 -0
  155. neverlib/.history/audio_aug/audio_aug_20250827153533.py +304 -0
  156. neverlib/.history/audio_aug/audio_aug_20250827153541.py +321 -0
  157. neverlib/.history/audio_aug/audio_aug_20250827153805.py +322 -0
  158. neverlib/.history/audio_aug/audio_aug_20250827153832.py +323 -0
  159. neverlib/.history/audio_aug/audio_aug_20250827153836.py +324 -0
  160. neverlib/.history/audio_aug/audio_aug_20250827153846.py +324 -0
  161. neverlib/.history/audio_aug/audio_aug_20250827153859.py +325 -0
  162. neverlib/.history/audio_aug/audio_aug_20250827154453.py +337 -0
  163. neverlib/.history/audio_aug/audio_aug_20250827154513.py +355 -0
  164. neverlib/.history/audio_aug/audio_aug_20250827154538.py +356 -0
  165. neverlib/.history/audio_aug/audio_aug_20250827154541.py +357 -0
  166. neverlib/.history/audio_aug/audio_aug_20250827154612.py +357 -0
  167. neverlib/.history/audio_aug/audio_aug_20250827154657.py +360 -0
  168. neverlib/.history/audio_aug/audio_aug_20250827154708.py +360 -0
  169. neverlib/.history/audio_aug/audio_aug_20250827154728.py +366 -0
  170. neverlib/.history/audio_aug/audio_aug_20250827154755.py +367 -0
  171. neverlib/.history/audio_aug/audio_aug_20250827154800.py +367 -0
  172. neverlib/.history/audio_aug/audio_aug_20250827154917.py +368 -0
  173. neverlib/.history/audio_aug/audio_aug_20250827154928.py +369 -0
  174. neverlib/.history/audio_aug/audio_aug_20250827154932.py +370 -0
  175. neverlib/.history/audio_aug/audio_aug_20250827154947.py +372 -0
  176. neverlib/.history/audio_aug/audio_aug_20250827155015.py +375 -0
  177. neverlib/.history/audio_aug/audio_aug_20250827155106.py +375 -0
  178. neverlib/.history/audio_aug/audio_aug_20250827155114.py +393 -0
  179. neverlib/.history/audio_aug/audio_aug_20250827155207.py +415 -0
  180. neverlib/.history/audio_aug/audio_aug_20250827155300.py +415 -0
  181. neverlib/.history/audio_aug/audio_aug_20250827155321.py +471 -0
  182. neverlib/.history/audio_aug/audio_aug_20250827164703.py +471 -0
  183. neverlib/.history/audio_aug/audio_aug_20250827164749.py +471 -0
  184. neverlib/.history/audio_aug/audio_aug_20250827165252.py +472 -0
  185. neverlib/.history/audio_aug/audio_aug_20250827165334.py +472 -0
  186. neverlib/.history/audio_aug/audio_aug_20250827165404.py +473 -0
  187. neverlib/.history/audio_aug/audio_aug_20250827165610.py +473 -0
  188. neverlib/.history/audio_aug/audio_aug_20250827165805.py +473 -0
  189. neverlib/.history/audio_aug/audio_aug_20250827170056.py +473 -0
  190. neverlib/.history/audio_aug/audio_aug_20250827170106.py +472 -0
  191. neverlib/.history/audio_aug/audio_aug_20250827170143.py +472 -0
  192. neverlib/.history/audio_aug/audio_aug_20250827170216.py +472 -0
  193. neverlib/.history/audio_aug/audio_aug_20250827170218.py +472 -0
  194. neverlib/.history/audio_aug/audio_aug_20250827170314.py +472 -0
  195. neverlib/.history/audio_aug/audio_aug_20250827171500.py +471 -0
  196. neverlib/.history/audio_aug/audio_aug_20250827172347.py +471 -0
  197. neverlib/.history/audio_aug/audio_aug_20250827172558.py +470 -0
  198. neverlib/.history/audio_aug/audio_aug_20250827172559.py +470 -0
  199. neverlib/.history/audio_aug/audio_aug_20250827172801.py +470 -0
  200. neverlib/.history/audio_aug/audio_aug_20250827182522.py +470 -0
  201. neverlib/.history/audio_aug/audio_aug_20250827182526.py +470 -0
  202. neverlib/.history/audio_aug/audio_aug_20250827182626.py +470 -0
  203. neverlib/.history/audio_aug/audio_aug_20250827182715.py +470 -0
  204. neverlib/.history/audio_aug/audio_aug_20250904185444.py +470 -0
  205. neverlib/.history/audio_aug/audio_aug_20250904185538.py +445 -0
  206. neverlib/.history/data_analyze/__init___20250806204158.py +14 -0
  207. neverlib/.history/data_analyze/__init___20250827163248.py +14 -0
  208. neverlib/.history/filter/auto_eq/freq_eq_20250821143140.py +76 -0
  209. neverlib/.history/filter/auto_eq/freq_eq_20250821153208.py +76 -0
  210. neverlib/.history/filter/auto_eq/freq_eq_20250821153214.py +76 -0
  211. neverlib/.history/filter/auto_eq/ga_eq_basic_20250901110521.py +385 -0
  212. neverlib/.history/filter/auto_eq/ga_eq_basic_20250901110652.py +385 -0
  213. neverlib/.history/filter/common_20250806002134.py +37 -0
  214. neverlib/.history/filter/common_20250821120448.py +49 -0
  215. neverlib/.history/filter/common_20250821120453.py +49 -0
  216. neverlib/.history/metrics/snr_20250827224201.py +182 -0
  217. neverlib/.history/metrics/snr_20250827234019.py +186 -0
  218. neverlib/.history/metrics/snr_20250827234028.py +186 -0
  219. neverlib/.history/metrics/snr_20250827234030.py +186 -0
  220. neverlib/.history/utils/audio_split_20250805234209.py +268 -0
  221. neverlib/.history/utils/audio_split_20250904185309.py +268 -0
  222. neverlib/.history/utils/utils_20250813165516.py +330 -0
  223. neverlib/.history/utils/utils_20250904181341.py +328 -0
  224. neverlib/.history/utils/utils_20250904185546.py +352 -0
  225. neverlib/.history/utils/utils_20250904185548.py +353 -0
  226. neverlib/.history/utils/utils_20250904185603.py +353 -0
  227. neverlib/.history/utils/utils_20250904185636.py +353 -0
  228. neverlib/.history/utils/utils_20250904185658.py +358 -0
  229. neverlib/.history/utils/utils_20250904190053.py +359 -0
  230. neverlib/.specstory/history/2025-08-22_02-10Z-/345/256/214/345/226/204/345/207/275/346/225/260/347/232/204/345/212/237/350/203/275/345/222/214/345/217/230/351/207/217/345/220/215/345/273/272/350/256/256.md +247 -0
  231. neverlib/.specstory/history/2025-08-26_11-54Z-oserror-missing-shared-object-file.md +87 -0
  232. neverlib/.specstory/history/2025-08-27_08-07Z-/345/256/214/345/226/204/346/265/213/350/257/225/346/226/207/346/241/243/347/232/204/350/256/250/350/256/272.md +296 -0
  233. neverlib/.specstory/history/2025-08-27_08-29Z-delete-python-file-command.md +211 -0
  234. neverlib/.specstory/history/2025-08-27_09-05Z-/345/234/250jupyter/344/270/255/346/222/255/346/224/276/351/237/263/351/242/221/347/232/204/344/273/243/347/240/201/344/277/256/346/224/271.md +357 -0
  235. neverlib/Docs/audio_aug_test/test_snr.py +55 -0
  236. neverlib/Docs/audio_aug_test/test_volume.py +0 -0
  237. neverlib/QA/html2markdown.py +27 -0
  238. neverlib/__init__.py +10 -20
  239. neverlib/audio_aug/__init__.py +6 -1
  240. neverlib/audio_aug/audio_aug.py +360 -55
  241. neverlib/data_analyze/__init__.py +8 -2
  242. neverlib/data_analyze/temporal_features.py +1 -1
  243. neverlib/filter/__init__.py +9 -3
  244. neverlib/filter/auto_eq/freq_eq.py +1 -1
  245. neverlib/filter/auto_eq/ga_eq_basic.py +3 -3
  246. neverlib/filter/common.py +12 -0
  247. neverlib/metrics/snr.py +5 -3
  248. neverlib/utils/__init__.py +14 -7
  249. neverlib/utils/lazy_module.py +81 -0
  250. neverlib/utils/message.py +3 -8
  251. neverlib/utils/utils.py +32 -3
  252. neverlib/vad/__init__.py +16 -9
  253. neverlib/vad/utils.py +20 -6
  254. {neverlib-0.2.4.dist-info → neverlib-0.2.6.dist-info}/METADATA +21 -17
  255. neverlib-0.2.6.dist-info/RECORD +467 -0
  256. neverlib-0.2.4.dist-info/RECORD +0 -229
  257. /neverlib/{Docs/audio_aug/test_snr.py → .history/Docs/audio_aug/test_snr_20250827162033.py} +0 -0
  258. {neverlib-0.2.4.dist-info → neverlib-0.2.6.dist-info}/WHEEL +0 -0
  259. {neverlib-0.2.4.dist-info → neverlib-0.2.6.dist-info}/licenses/LICENSE +0 -0
  260. {neverlib-0.2.4.dist-info → neverlib-0.2.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,186 @@
1
+ import librosa
2
+ import numpy as np
3
+ from neverlib.vad.utils import vad2nad
4
+ from neverlib.filter import HPFilter
5
+
6
+
7
+ def get_snr(speech, noise, hpf=False, sr=16000, order=6, cutoff=100):
8
+ """计算信噪比
9
+ Args:
10
+ speech: 语音音频
11
+ noise: 噪声音频
12
+ Returns:
13
+ snr: 信噪比
14
+ """
15
+ assert speech.ndim == noise.ndim, "speech和noise的维度不一样"
16
+ if hpf:
17
+ speech = HPFilter(speech, sr=sr, order=order, cutoff=cutoff)
18
+ noise = HPFilter(noise, sr=sr, order=order, cutoff=cutoff)
19
+
20
+ power_speech = np.mean(speech**2)
21
+ power_noise = max(np.mean(noise**2), 1e-10)
22
+
23
+ snr = 10 * np.log10(power_speech / power_noise)
24
+ return snr
25
+
26
+
27
+ def get_snr_from_noisy(noisy, speech_vad=None):
28
+ """根据带噪音频计算信噪比
29
+ Args:
30
+ noisy: 带噪音频
31
+ speech_vad: [{start:xxx, end:xxx}, ...]
32
+ Returns:
33
+ snr: 信噪比
34
+ """
35
+ assert speech_vad is not None, "speech_vad不能为空"
36
+
37
+ # 提取语音段
38
+ speech_segments = []
39
+ for segment in speech_vad:
40
+ start = segment['start']
41
+ end = segment['end']
42
+ speech_segments.append(noisy[start:end])
43
+ speech = np.concatenate(speech_segments, axis=0)
44
+
45
+ # 提取非语音段
46
+ noise_segments = []
47
+ noise_point_list = vad2nad(speech_vad, len(noisy))
48
+ for noise_point in noise_point_list:
49
+ noise_segments.append(noisy[noise_point['start']:noise_point['end']])
50
+ noise = np.concatenate(noise_segments, axis=0)
51
+
52
+ P_speech_noise = np.mean(speech ** 2) # 语音+噪声功率
53
+ P_noise = max(np.mean(noise ** 2), EPS) # 纯噪声功率
54
+
55
+ # 计算净语音功率
56
+ P_speech = max(P_speech_noise - P_noise, EPS)
57
+ snr = 10 * np.log10(P_speech / P_noise)
58
+
59
+ return snr
60
+
61
+
62
+ def seg_snr(clean, noisy, frame_length: int, hop_length: int):
63
+ """
64
+ 分帧计算信噪比
65
+ Args:
66
+ clean: 干净音频, numpy array
67
+ noisy: 带噪音频, numpy array
68
+ frame_length: 帧长
69
+ hop_length: 帧移
70
+ Returns:
71
+ snr_mean: 平均信噪比, float
72
+ Raises:
73
+ ValueError: 当输入参数不合法时抛出
74
+ """
75
+ assert clean.shape == noisy.shape, "clean和noisy的维度不一样"
76
+
77
+ # 分帧
78
+ clean_frames = librosa.util.frame(clean, frame_length=frame_length, hop_length=hop_length) # (frame_length, n_frames)
79
+ noisy_frames = librosa.util.frame(noisy, frame_length=frame_length, hop_length=hop_length) # (frame_length, n_frames)
80
+
81
+ # 计算每帧的信噪比
82
+ snr_frames = []
83
+ for i in range(clean_frames.shape[1]):
84
+ clean_frame = clean_frames[:, i]
85
+ noisy_frame = noisy_frames[:, i]
86
+ # 跳过静音帧
87
+ if np.all(np.abs(clean_frame) < 1e-6) or np.all(np.abs(noisy_frame) < 1e-6):
88
+ continue
89
+ snr_frames.append(get_snr(clean_frame, noisy_frame))
90
+
91
+ # 如果所有帧都是静音
92
+ if not snr_frames:
93
+ return float('-inf')
94
+
95
+ return np.mean(snr_frames)
96
+
97
+
98
+ def psnr(clean, noisy, max_val=None):
99
+ """
100
+ 计算峰值信噪比
101
+ Args:
102
+ clean: 干净音频, numpy array
103
+ noisy: 带噪音频, numpy array
104
+ max_val: 信号最大值, 如果为None则使用clean信号的实际最大值
105
+ Returns:
106
+ psnr: 峰值信噪比, 单位dB
107
+ """
108
+ assert clean.shape == noisy.shape, "clean和noisy的维度不一样"
109
+
110
+ # 如果没有指定最大值, 使用clean信号的实际最大值
111
+ if max_val is None:
112
+ max_val = np.abs(clean).max()
113
+
114
+ # 计算均方误差 (MSE)
115
+ mse = np.mean((clean - noisy) ** 2)
116
+
117
+ # 避免除以0
118
+ if mse == 0:
119
+ return float('inf')
120
+
121
+ # 计算PSNR
122
+ psnr = 10 * np.log10(max_val**2 / mse)
123
+ return psnr
124
+
125
+
126
+ def si_sdr(reference, estimate, epsilon=1e-8):
127
+ """
128
+ 计算尺度不变信噪比 (Scale-Invariant Signal-to-Distortion Ratio, SI-SDR)。
129
+
130
+ Args:
131
+ reference (np.ndarray): 原始的、干净的参考信号 (一维数组)。
132
+ estimate (np.ndarray): 模型估计或处理后的信号 (一维数组)。
133
+ epsilon (float): 一个非常小的数值, 用于防止分母为零, 保证数值稳定性。
134
+
135
+ Returns:
136
+ float: SI-SDR 值, 单位为分贝 (dB)。
137
+ """
138
+ assert reference.shape == estimate.shape, "reference和estimate的维度不一样"
139
+
140
+ # 2. 零均值化 (可选但推荐)
141
+ # 移除直流分量, 使计算更关注信号的动态变化
142
+ reference = reference - np.mean(reference)
143
+ estimate = estimate - np.mean(estimate)
144
+
145
+ # 3. 计算目标信号分量 (s_target)
146
+ # s_target 是 estimate 在 reference 上的投影
147
+ # 公式: s_target = (<ŝ, s> / ||s||²) * s
148
+ dot_product = np.dot(estimate, reference) # <ŝ, s> (点积)
149
+ norm_s_squared = np.dot(reference, reference) # ||s||² (s的能量)
150
+
151
+ # 检查参考信号能量, 避免除以零
152
+ if norm_s_squared < epsilon:
153
+ # 如果参考信号几乎是静音, SI-SDR没有意义
154
+ return -np.inf # 返回负无穷或np.nan
155
+
156
+ alpha = dot_product / (norm_s_squared + epsilon) # 最佳缩放因子 α
157
+ s_target = alpha * reference
158
+
159
+ # 4. 计算误差/失真分量 (e_noise)
160
+ e_noise = estimate - s_target
161
+
162
+ # 5. 计算 SI-SDR
163
+ # SI-SDR = 10 * log10 ( ||s_target||² / ||e_noise||² )
164
+ power_s_target = np.sum(s_target**2) # ||s_target||²
165
+ power_e_noise = np.sum(e_noise**2) # ||e_noise||²
166
+
167
+ # 同样加上 epsilon 防止除以零
168
+ if power_e_noise < epsilon:
169
+ # 如果噪声能量极小, 说明匹配得非常好
170
+ return np.inf # 返回正无穷
171
+
172
+ si_sdr_val = 10 * np.log10(power_s_target / (power_e_noise + epsilon))
173
+
174
+ return si_sdr_val
175
+
176
+
177
+ if __name__ == "__main__":
178
+ # 生成测试信号
179
+ speech = np.random.randn(1000)
180
+ noise = np.random.randn(1000) * 0.1 # 较小的噪声
181
+ noisy = speech + noise
182
+
183
+ # 测试各种信噪比计算方法
184
+ print(f"SNR: {get_snr(speech, noise):.2f} dB")
185
+ print(f"Segmental SNR: {seg_snr(speech, noisy, 100, 50):.2f} dB")
186
+ print(f"PSNR: {psnr(speech, noisy):.2f} dB")
@@ -0,0 +1,268 @@
1
+ '''
2
+ Author: 凌逆战 | Never
3
+ Date: 2025-04-10 18:07:03
4
+ Description: 音频切割
5
+ '''
6
+ import os
7
+ import random
8
+ import subprocess
9
+ from tqdm import tqdm
10
+ import soundfile as sf
11
+ import numpy as np
12
+ from .utils import get_path_list
13
+ from pydub import AudioSegment
14
+
15
+
16
+ def audio_split_ffmpeg(source_path, target_path, sr, channel_num, duration, endwith="*.pcm"):
17
+ """ 切割音频切不准, 会留点尾巴0.016s
18
+ 使用ffmpeg分割音频, 分割为短音频(单位:秒), 似乎无法非常准确的分割到指定长度
19
+ :param source_path: 源音频路径
20
+ :param target_path: 目标音频路径
21
+ :param sr: 源音频采样率
22
+ :param channel_num: 源音频声道数
23
+ :param duration: 分割为时长(短音频)(单位:秒)
24
+ :param endwith: 音频格式(支持pcm和wav)
25
+ """
26
+ wav_path_list = get_path_list(source_path, end=endwith)
27
+ print("待分割的音频数: ", len(wav_path_list))
28
+ for wav_path in wav_path_list:
29
+ wav_folder = wav_path[:-4].replace(source_path, target_path)
30
+ os.makedirs(wav_folder, exist_ok=True)
31
+
32
+ if endwith == "*.pcm":
33
+ # 将pcm文件切割成30s的语音, 有括号会报错
34
+ # ffmpeg -f s16le -ar 16000 -ac 6 -i ./NO.1_A3035_2.pcm -f segment -segment_time 30 -c copy NO.1_A3035_2/%03d.wav
35
+ command = ["ffmpeg", "-f", "s16le", "-ar", f"{sr}", "-ac", str(channel_num),
36
+ "-i", wav_path, "-f", "segment", "-segment_time",
37
+ f"{duration}", "-c", "copy", f"{wav_folder}/%03d.wav"]
38
+ subprocess.run(command, check=True)
39
+ elif endwith == "*.wav":
40
+ # ffmpeg -i ./NO.1_A3035_2.wav -f segment -segment_time 30 -c copy NO.1_A3035_2/%03d.wav
41
+ command = ["ffmpeg", "-i", wav_path, "-f", "segment", "-segment_time",
42
+ f"{duration}", "-c", "copy", f"{wav_folder}/%03d.wav"]
43
+ subprocess.run(command, check=True)
44
+ else:
45
+ assert False, "不支持的音频格式"
46
+ print("分割完毕: done!")
47
+
48
+
49
+ def audio_split_sox(source_path, target_path, duration, endwith="*.wav"):
50
+ """
51
+ 使用sox分割音频, 分割为短音频(单位:秒), 可以非常准确的分割到指定长度
52
+ :param source_path: 源音频路径
53
+ :param target_path: 目标音频路径
54
+ :param duration: 分割为时长(短音频)(单位:秒)
55
+ :param endwith: 音频格式(只支持wav)
56
+ """
57
+ wav_path_list = get_path_list(source_path, end=endwith)
58
+
59
+ for wav_path in wav_path_list:
60
+ wav_folder = wav_path[:-4].replace(source_path, target_path)
61
+ os.makedirs(wav_folder, exist_ok=True)
62
+
63
+ output_pattern = f"{wav_folder}/%.wav"
64
+
65
+ if endwith == "*.wav":
66
+ # 对 WAV 文件直接进行分割
67
+ os.system(f"sox {wav_path} {output_pattern} trim 0 {str(duration)} : newfile : restart")
68
+ else:
69
+ assert False, "不支持的音频格式"
70
+
71
+ print("分割完毕: done!")
72
+
73
+
74
+ def audio_split_np(source_path, target_path, sr, channel_num, duration, endwith="*.pcm"):
75
+ """
76
+ 使用numpy读取pcm文件并切割保存为wav文件, 保持通道数一致, 保存不足30秒的最后一段音频
77
+ :param source_path: 源音频路径
78
+ :param target_path: 目标音频路径
79
+ :param sr: 采样率
80
+ :param channel_num: 声道数
81
+ :param duration: 分割的时长 (秒)
82
+ :param endwith: 音频格式 (支持 pcm)
83
+ """
84
+ assert endwith == "*.pcm", "只支持pcm格式的音频"
85
+ wav_path_list = get_path_list(source_path, end=endwith) # 获取音频文件列表
86
+ print("待分割的音频数: ", len(wav_path_list))
87
+
88
+ segment_length_samples = duration * sr # 每个切片音频的采样点数
89
+
90
+ for wav_path in wav_path_list:
91
+ print("正在分割: ", wav_path)
92
+ wav_folder = wav_path[:-4].replace(source_path, target_path)
93
+ os.makedirs(wav_folder, exist_ok=True)
94
+
95
+ # 注意读取时使用正确的dtype(例如int16表示16位PCM)
96
+ pcm_data = np.fromfile(wav_path, dtype=np.int16)
97
+ pcm_data = pcm_data[:(len(pcm_data) // channel_num) * channel_num]
98
+ pcm_data = pcm_data.reshape(-1, channel_num)
99
+
100
+ # 计算分割的数量
101
+ num_segments = len(pcm_data) // segment_length_samples
102
+
103
+ # 切割并保存每段音频
104
+ for i in tqdm(range(num_segments)):
105
+ start_idx = i * segment_length_samples
106
+ end_idx = (i + 1) * segment_length_samples
107
+ segment = pcm_data[start_idx:end_idx]
108
+ segment_filename = os.path.join(wav_folder, f"{i + 1:03d}.wav") # 保存为wav文件
109
+ sf.write(segment_filename, segment, sr, subtype='PCM_16')
110
+
111
+ # 如果剩余部分少于30秒, 保存最后一段不足30秒的音频
112
+ remaining_samples = len(pcm_data) % segment_length_samples
113
+ if remaining_samples > 0:
114
+ segment = pcm_data[-remaining_samples:]
115
+ # 保存剩余部分
116
+ remaining_filename = os.path.join(wav_folder, f"{num_segments + 1:03d}.wav")
117
+ sf.write(remaining_filename, segment, sr, subtype='PCM_16')
118
+
119
+ print("分割完毕: done!")
120
+
121
+
122
+ def audio_split_pydub(source_path, target_path, sr, channel_num, duration, endwith="*.pcm", sample_width=2):
123
+ """
124
+ 使用pydub分割音频, 进行精确的分割
125
+ :param source_path: 源音频路径
126
+ :param target_path: 目标音频路径
127
+ :param sr: 源音频采样率
128
+ :param channel_num: 源音频声道数
129
+ :param duration: 分割为时长(短音频)(单位:秒), 必须是1s的整数倍
130
+ :param endwith: 音频格式(支持pcm和wav)
131
+ :param sample_width: 音频的样本宽度(字节数), 默认为2, 表示16位音频
132
+ """
133
+ assert duration % 1 == 0, "duration必须是1s的整数倍"
134
+ wav_path_list = get_path_list(source_path, end=endwith) # 获取音频文件列表
135
+ print("待分割的音频数: ", len(wav_path_list))
136
+
137
+ for wav_path in wav_path_list:
138
+ print("正在分割: ", wav_path)
139
+ wav_folder = wav_path[:-4].replace(source_path, target_path) # 设置目标文件夹
140
+ os.makedirs(wav_folder, exist_ok=True)
141
+
142
+ # 使用pydub加载音频
143
+ if endwith == "*.pcm":
144
+ # 读取pcm文件, 指定采样率、声道数和样本宽度
145
+ audio = AudioSegment.from_file(wav_path, format="raw", channels=channel_num, frame_rate=sr, sample_width=sample_width)
146
+ elif endwith == "*.wav":
147
+ # 读取wav文件
148
+ audio = AudioSegment.from_wav(wav_path)
149
+ else:
150
+ assert False, "不支持的音频格式"
151
+
152
+ # 计算每段的时长(以毫秒为单位)
153
+ segment_length = duration * 1000 # 转换为毫秒
154
+
155
+ # 切割音频并保存为多个文件
156
+ segment_number = 1
157
+ for i in tqdm(range(0, len(audio), segment_length)):
158
+ segment = audio[i:i + segment_length]
159
+ segment_filename = os.path.join(wav_folder, f"{segment_number:03d}.wav")
160
+ segment.export(segment_filename, format="wav")
161
+ segment_number += 1
162
+
163
+ print("分割完毕: done!")
164
+
165
+
166
+ def audio_split_random(source_dir, target_dir, min_duration=3, max_duration=10, sr=16000):
167
+ """
168
+ 将音频切割成 3 到 10 秒的多个片段并保存。
169
+ 参数:
170
+ - input_audio_path: 输入音频文件路径
171
+ - output_dir: 输出音频文件夹路径
172
+ - min_duration: 最短切割片段长度 (秒), 默认3秒
173
+ - max_duration: 最长切割片段长度 (秒), 默认10秒
174
+ - sample_rate: 采样率, 默认16000
175
+ """
176
+ wav_path_list = get_path_list(source_dir, "*.wav")
177
+ for wav_path in wav_path_list:
178
+ output_dir = wav_path[:-4].replace(source_dir, target_dir)
179
+ os.makedirs(output_dir, exist_ok=True)
180
+
181
+ wav, wav_sr = sf.read(wav_path, always_2d=True)
182
+ assert wav_sr == sr, f"音频采样率不匹配: {wav_sr} != {sr}"
183
+ count = 0
184
+ while len(wav) > max_duration * sr:
185
+ segment_len = random.randint(min_duration * sr, max_duration * sr)
186
+ segment = wav[0: segment_len]
187
+ wav = wav[segment_len:]
188
+ count += 1
189
+ sf.write(os.path.join(output_dir, f"{count}.wav"), segment, sr)
190
+ sf.write(os.path.join(output_dir, f"{count + 1}.wav"), wav, sr)
191
+
192
+
193
+ def audio_split_VADfunasr(source_dir, target_dir, sr=16000):
194
+ """
195
+ 使用funasr的vad模型将音频中的语音分割成短句
196
+ """
197
+ from filter import HPFilter
198
+ from audio_aug import volume_norm
199
+ from funasr import AutoModel
200
+ model = AutoModel(model="fsmn-vad", model_revision="v2.0.4")
201
+
202
+ wav_path_list = get_path_list(source_dir, "*.wav")
203
+ for wav_path in wav_path_list:
204
+ wav_folder = wav_path[:-4].replace(source_dir, target_dir)
205
+ os.makedirs(wav_folder, exist_ok=True)
206
+
207
+ wav_orig, wav_sr = sf.read(wav_path, always_2d=True)
208
+ assert wav_sr == sr, f"音频采样率为{wav_sr}, 期望为{sr}"
209
+
210
+ wav = HPFilter(wav_orig[:, 0], sr=sr, order=6, cutoff=100)
211
+ wav = volume_norm(wav)
212
+
213
+ res_list = model.generate(input=wav)
214
+
215
+ for res in res_list:
216
+ for i, value_item in enumerate(res["value"]):
217
+ start, end = value_item
218
+ start, end = int(start * wav_sr / 1000), int(end * wav_sr / 1000)
219
+
220
+ # short_wav = wav_orig[start - int(0.5 * sr):end + int(0.5 * sr)]
221
+ # duration = (end - start) / sr
222
+ # assert len(short_wav) > sr * 3, f"{end/sr:.2f}-{start/sr:.2f}={duration:.2f}"
223
+ sf.write(os.path.join(wav_folder, f"{i}.wav"), wav_orig[start:end], sr)
224
+ # break
225
+
226
+
227
+ def audio_split_VADsilero(source_dir, target_dir, sr, threshold=0.4,
228
+ min_speech_duration_ms=400, min_silence_duration_ms=400,
229
+ window_size_samples=512, speech_pad_ms=500):
230
+ """
231
+ 使用silero的vad模型将音频中的语音分割成短句
232
+ source_dir: 音频文件目录
233
+ target_dir: 分割后的音频文件目录
234
+ sr: 音频采样率
235
+ threshold: 阈值
236
+ min_speech_duration_ms: 语音块的最小持续时间 ms
237
+ min_silence_duration_ms: 语音块之间的最小静音时间 ms
238
+ window_size_samples: 512\1024\1536
239
+ """
240
+ import torch
241
+ from filter import HPFilter
242
+ from audio_aug import volume_norm
243
+ model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad', model='silero_vad', force_reload=False, onnx=True)
244
+ (get_speech_timestamps, save_audio, read_audio, VADIterator, collect_chunks) = utils
245
+
246
+ wav_path_list = get_path_list(source_dir, "*.wav")
247
+ for wav_path in wav_path_list:
248
+ wav_folder = wav_path[:-4].replace(source_dir, target_dir)
249
+ os.makedirs(wav_folder, exist_ok=True)
250
+
251
+ wav_orig, wav_sr = sf.read(wav_path, always_2d=True)
252
+ assert wav_sr == sr, f"音频采样率为{wav_sr}, 期望为{sr}"
253
+
254
+ wav = HPFilter(wav_orig[:, 0], sr=sr, order=6, cutoff=100)
255
+ wav = volume_norm(wav)
256
+
257
+ speech_timestamps = get_speech_timestamps(wav, model,
258
+ sampling_rate=sr,
259
+ threshold=threshold,
260
+ min_speech_duration_ms=min_speech_duration_ms, # 语音块的最小持续时间 ms
261
+ min_silence_duration_ms=min_silence_duration_ms, # 语音块之间的最小静音时间 ms
262
+ window_size_samples=window_size_samples, # 512\1024\1536
263
+ speech_pad_ms=speech_pad_ms, # 最后的语音块由两侧的speech_pad_ms填充
264
+ )
265
+ for i, timestamp in enumerate(speech_timestamps):
266
+ wav_vad = wav_orig[timestamp["start"]:timestamp["end"]]
267
+
268
+ sf.write(os.path.join(wav_folder, f"{i}.wav"), wav_vad, sr)