ssasio commited on
Commit
8c2f37b
·
verified ·
1 Parent(s): 19a2e3d

Upload audio_enhance.py

Browse files
Files changed (1) hide show
  1. audio_enhance.py +141 -0
audio_enhance.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """audio_enhance.py — Voice cloning audio preprocessor
2
+ =======================================================
3
+ Прилага 3 стъпки преди CODEC encode при клониране на глас:
4
+ 1. Noise reduction — премахва фонов шум (spectral gating)
5
+ 2. De-essing — намалява съскането (5–10 kHz notch)
6
+ 3. Warming — леко усилва ниските средни (200–800 Hz)
7
+
8
+ Всичко работи само с numpy + scipy (без външни зависимости).
9
+ noisereduce е опционален — ако не е инсталиран, се пропуска стъпка 1.
10
+ """
11
+
12
+ import numpy as np
13
+ from scipy import signal as sig
14
+
15
+
16
+ # ── 1. Noise reduction ────────────────────────────────────────
17
+ def reduce_noise(audio: np.ndarray, sr: int, prop_decrease: float = 0.75) -> np.ndarray:
18
+ """
19
+ Spectral gating noise reduction.
20
+ prop_decrease: 0.0 = без ефект, 1.0 = пълно заглушаване на шума.
21
+ По-консервативна стойност (0.75) запазва естествеността на гласа.
22
+ """
23
+ try:
24
+ import noisereduce as nr
25
+ # non-stationary = следи шума динамично (по-добре за записи с вариращ шум)
26
+ reduced = nr.reduce_noise(
27
+ y=audio,
28
+ sr=sr,
29
+ prop_decrease=prop_decrease,
30
+ stationary=False,
31
+ freq_mask_smooth_hz=500,
32
+ time_mask_smooth_ms=50,
33
+ )
34
+ return reduced.astype(np.float32)
35
+ except ImportError:
36
+ # noisereduce не е инсталиран — пропускаме стъпката
37
+ print(" [enhance] noisereduce не е намерен — пропускане на noise reduction")
38
+ return audio
39
+
40
+
41
+ # ── 2. De-esser (намаляване на съскане) ──────────────────────
42
+ def de_ess(audio: np.ndarray, sr: int,
43
+ freq_low: float = 5000.0,
44
+ freq_high: float = 10000.0,
45
+ reduction_db: float = 6.0) -> np.ndarray:
46
+ """
47
+ Намалява съскащите честоти (сибиланс) чрез band-stop EQ.
48
+ freq_low / freq_high: диапазон на съскането в Hz (обикновено 5–10 kHz).
49
+ reduction_db: колко dB да намали (6 dB = наполовина по амплитуда).
50
+ """
51
+ nyq = sr / 2.0
52
+ low = freq_low / nyq
53
+ high = freq_high / nyq
54
+
55
+ # Клипваме до валиден диапазон
56
+ low = max(0.01, min(low, 0.98))
57
+ high = max(low + 0.01, min(high, 0.99))
58
+
59
+ # Band-stop (notch) филтър
60
+ b, a = sig.butter(2, [low, high], btype='bandstop')
61
+ filtered = sig.filtfilt(b, a, audio).astype(np.float32)
62
+
63
+ # Смесваме — не заместваме изцяло, за да запазим натуралност
64
+ gain = 10 ** (-reduction_db / 20.0) # amplitude gain за подтиснатия обхват
65
+ # Изчисляваме само sibilant band и го добавяме обратно редуциран
66
+ sibilant = audio - filtered # само съскащите честоти
67
+ result = filtered + sibilant * gain # filtered + намален сибилант
68
+ return result.astype(np.float32)
69
+
70
+
71
+ # ── 3. Warming (топлина на гласа) ────────────────────────────
72
+ def warm_voice(audio: np.ndarray, sr: int,
73
+ freq_low: float = 200.0,
74
+ freq_high: float = 800.0,
75
+ boost_db: float = 2.5) -> np.ndarray:
76
+ """
77
+ Леко усилва ниско-средните честоти (200–800 Hz) за по-топъл глас.
78
+ boost_db: колко dB усилване (2–3 dB е естествено, над 4 е прекалено).
79
+ """
80
+ nyq = sr / 2.0
81
+ low = freq_low / nyq
82
+ high = freq_high / nyq
83
+
84
+ low = max(0.01, min(low, 0.98))
85
+ high = max(low + 0.01, min(high, 0.99))
86
+
87
+ # Band-pass — изолираме средните
88
+ b, a = sig.butter(2, [low, high], btype='bandpass')
89
+ warm_band = sig.filtfilt(b, a, audio).astype(np.float32)
90
+
91
+ gain = 10 ** (boost_db / 20.0) - 1.0 # само добавката (gain - 1)
92
+ result = audio + warm_band * gain
93
+ return result.astype(np.float32)
94
+
95
+
96
+ # ── 4. Нормализация ───────────────────────────────────────────
97
+ def normalize(audio: np.ndarray, target_peak: float = 0.95) -> np.ndarray:
98
+ """Пиково нормализиране — не позволява клипване след EQ."""
99
+ peak = np.max(np.abs(audio))
100
+ if peak > 1e-6:
101
+ audio = audio / peak * target_peak
102
+ return audio.astype(np.float32)
103
+
104
+
105
+ # ── 5. Главна функция ─────────────────────────────────────────
106
+ def enhance_voice_for_cloning(
107
+ audio: np.ndarray,
108
+ sr: int,
109
+ do_denoise: bool = True,
110
+ do_deess: bool = True,
111
+ do_warm: bool = True,
112
+ denoise_strength: float = 0.75, # 0.0–1.0
113
+ deess_reduction_db: float = 6.0, # dB намаляване на съскане
114
+ warm_boost_db: float = 2.5, # dB усилване на топлина
115
+ ) -> np.ndarray:
116
+ """
117
+ Пълен pipeline за почистване на референтен глас преди клониране.
118
+ Връща почистено np.float32 аудио.
119
+ """
120
+ # Осигуряваме float32 mono
121
+ audio = audio.astype(np.float32)
122
+ if audio.ndim > 1:
123
+ audio = audio.mean(axis=0) # stereo → mono
124
+
125
+ print(f" [enhance] Входен сигнал: {len(audio)/sr:.1f}s @ {sr}Hz")
126
+
127
+ if do_denoise:
128
+ print(f" [enhance] Noise reduction (сила={denoise_strength:.0%})...")
129
+ audio = reduce_noise(audio, sr, prop_decrease=denoise_strength)
130
+
131
+ if do_deess:
132
+ print(f" [enhance] De-essing ({deess_reduction_db:.0f}dB)...")
133
+ audio = de_ess(audio, sr, reduction_db=deess_reduction_db)
134
+
135
+ if do_warm:
136
+ print(f" [enhance] Warming (+{warm_boost_db:.1f}dB @ 200–800Hz)...")
137
+ audio = warm_voice(audio, sr, boost_db=warm_boost_db)
138
+
139
+ audio = normalize(audio)
140
+ print(" [enhance] Готово ✓")
141
+ return audio