ongudidan commited on
Commit
6cd9ca2
·
1 Parent(s): 6d7d479

refactor: simplify audio post-processing to fixed filters and remove redundant UI controls

Browse files
Files changed (1) hide show
  1. app.py +17 -88
app.py CHANGED
@@ -129,47 +129,15 @@ def ensure_wav(filepath: str) -> str:
129
 
130
  import torchaudio.functional as F_audio
131
 
132
- def post_process_audio(
133
- waveform: Tensor,
134
- sr: int,
135
- low_cut_freq: float,
136
- bass_gain: float,
137
- treble_gain: float,
138
- gate_threshold: float,
139
- enable_warmth: bool,
140
- ) -> Tensor:
141
  """Apply professional DSP filters to make voice audio crisp and clear."""
142
- # 1. High-pass filter (Low-cut) to cut sub-bass rumble and AC hums
143
- if low_cut_freq > 20:
144
- waveform = F_audio.highpass_biquad(waveform, sample_rate=sr, cutoff_freq=low_cut_freq)
145
-
146
- # 2. Bass EQ peaking filter at 150 Hz to add warmth or reduce muddiness
147
- if bass_gain != 0:
148
- waveform = F_audio.equalizer_biquad(waveform, sample_rate=sr, center_freq=150.0, gain=bass_gain, Q=0.707)
149
-
150
- # 3. Treble EQ peaking filter at 6000 Hz to add air, presence, and vocal crispness
151
- if treble_gain != 0:
152
- waveform = F_audio.equalizer_biquad(waveform, sample_rate=sr, center_freq=6000.0, gain=treble_gain, Q=0.707)
153
-
154
- # 4. Soft Noise Gate to remove background gating/watery artifacts during silence
155
- if gate_threshold > -60.0:
156
- threshold = 10 ** (gate_threshold / 20.0)
157
- envelope = waveform.abs()
158
- # Smooth envelope using 50ms average pooling
159
- win_size = int(sr * 0.05)
160
- if win_size % 2 == 0:
161
- win_size += 1
162
- env_padded = torch.nn.functional.pad(envelope, (win_size//2, win_size//2), mode='reflect')
163
- env_smooth = torch.nn.functional.avg_pool1d(env_padded.unsqueeze(0), kernel_size=win_size, stride=1).squeeze(0)
164
- # Soft sigmoid gating to prevent clicking
165
- gain = torch.sigmoid((env_smooth - threshold) / (threshold * 0.25))
166
- waveform = waveform * gain
167
-
168
- # 5. Analog Warmth (Soft Saturation / Tube Limiting)
169
- if enable_warmth:
170
- waveform = torch.tanh(waveform * 1.05) / 1.05
171
-
172
- # 6. Normalize peak to -1.0 dBFS (0.9 max amplitude) to maximize volume without clipping
173
  max_val = waveform.abs().max()
174
  if max_val > 0:
175
  waveform = waveform * (0.9 / max_val)
@@ -178,25 +146,19 @@ def post_process_audio(
178
 
179
 
180
  def demo_fn(
181
- input_type: str,
182
  speech_upl: str,
183
  noise_type: str,
184
  snr: int,
185
  atten_lim_db: float,
186
  wet_dry_mix: float,
187
  post_process: bool,
188
- low_cut_freq: float,
189
- bass_gain: float,
190
- treble_gain: float,
191
- gate_threshold: float,
192
- enable_warmth: bool,
193
  mic_input: Optional[str] = None,
194
  ):
195
- if input_type == "mic":
196
  speech_upl = mic_input
197
 
198
  sr = config("sr", 48000, int, section="df")
199
- logger.info(f"Got parameters input_type: {input_type}, speech_upl: {speech_upl}, noise: {noise_type}, snr: {snr}, atten_lim_db: {atten_lim_db}, wet_dry_mix: {wet_dry_mix}, post_process: {post_process}, low_cut: {low_cut_freq}, bass: {bass_gain}, treble: {treble_gain}, gate: {gate_threshold}, warmth: {enable_warmth}")
200
  snr = int(snr)
201
  noise_fn = NOISES[noise_type]
202
  meta = AudioMetaData(-1, -1, -1, -1, "")
@@ -242,9 +204,9 @@ def demo_fn(
242
  alpha = wet_dry_mix / 100.0
243
  enhanced = alpha * enhanced + (1 - alpha) * sample
244
 
245
- # Apply professional post-processing (Low-cut filter + bass EQ + treble EQ + gate + warmth)
246
  if post_process:
247
- enhanced = post_process_audio(enhanced, sr, low_cut_freq, bass_gain, treble_gain, gate_threshold, enable_warmth)
248
 
249
  lim = torch.linspace(0.0, 1.0, int(sr * 0.15)).unsqueeze(0)
250
  lim = torch.cat((lim, torch.ones(1, enhanced.shape[-1] - lim.shape[1])), dim=1)
@@ -412,7 +374,6 @@ with gr.Blocks() as demo:
412
  mic_input = gr.Mic(label="Input", type="filepath", visible=False)
413
  audio_file = gr.Audio(type="filepath", label="Input", visible=True)
414
  inputs = [
415
- radio,
416
  audio_file,
417
  gr.Dropdown(
418
  label="Add background noise",
@@ -439,39 +400,7 @@ with gr.Blocks() as demo:
439
  label="Voice Naturalness Mix (%) - 100% is fully denoised, 90% blends back some original voice",
440
  ),
441
  gr.Checkbox(
442
- label="Enable Post-Processing EQ & Filters",
443
- value=True,
444
- ),
445
- gr.Slider(
446
- minimum=20,
447
- maximum=200,
448
- step=10,
449
- value=80,
450
- label="Low-Cut Filter Cutoff (Hz) - cuts muddy AC rumble/handling noise",
451
- ),
452
- gr.Slider(
453
- minimum=-10,
454
- maximum=10,
455
- step=1,
456
- value=0,
457
- label="Voice Bass EQ Boost (dB) at 150Hz - adds warmth",
458
- ),
459
- gr.Slider(
460
- minimum=-10,
461
- maximum=10,
462
- step=1,
463
- value=3,
464
- label="Voice Treble EQ Boost (dB) at 6kHz - adds crispness/air",
465
- ),
466
- gr.Slider(
467
- minimum=-60,
468
- maximum=-30,
469
- step=5,
470
- value=-45,
471
- label="Noise Gate Threshold (dB) - lower keeps quiet sound, higher silences gaps",
472
- ),
473
- gr.Checkbox(
474
- label="Enable Analog Warmth (Soft Saturation)",
475
  value=True,
476
  ),
477
  mic_input,
@@ -490,10 +419,10 @@ with gr.Blocks() as demo:
490
  radio.change(toggle, radio, [mic_input, audio_file])
491
  gr.Examples(
492
  [
493
- ["file", "./samples/p232_013_clean.wav", "Kitchen", "10", 15, 90, True, 80, 0, 3, -45, True, None],
494
- ["file", "./samples/p232_013_clean.wav", "Cafe", "10", 15, 90, True, 80, 0, 3, -45, True, None],
495
- ["file", "./samples/p232_019_clean.wav", "Cafe", "10", 15, 90, True, 80, 0, 3, -45, True, None],
496
- ["file", "./samples/p232_019_clean.wav", "River", "10", 15, 90, True, 80, 0, 3, -45, True, None],
497
  ],
498
  fn=demo_fn,
499
  inputs=inputs,
 
129
 
130
  import torchaudio.functional as F_audio
131
 
132
+ def post_process_audio(waveform: Tensor, sr: int) -> Tensor:
 
 
 
 
 
 
 
 
133
  """Apply professional DSP filters to make voice audio crisp and clear."""
134
+ # 1. High-pass filter at 80 Hz to cut muddy sub-bass rumble and AC hums
135
+ waveform = F_audio.highpass_biquad(waveform, sample_rate=sr, cutoff_freq=80.0)
136
+
137
+ # 2. Treble peaking equalizer at 6000 Hz (+3.0 dB) to add air, presence, and vocal crispness
138
+ waveform = F_audio.equalizer_biquad(waveform, sample_rate=sr, center_freq=6000.0, gain=3.0, Q=0.707)
139
+
140
+ # 3. Normalize peak to -1.0 dBFS (0.9 max amplitude) to maximize volume without clipping
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  max_val = waveform.abs().max()
142
  if max_val > 0:
143
  waveform = waveform * (0.9 / max_val)
 
146
 
147
 
148
  def demo_fn(
 
149
  speech_upl: str,
150
  noise_type: str,
151
  snr: int,
152
  atten_lim_db: float,
153
  wet_dry_mix: float,
154
  post_process: bool,
 
 
 
 
 
155
  mic_input: Optional[str] = None,
156
  ):
157
+ if mic_input:
158
  speech_upl = mic_input
159
 
160
  sr = config("sr", 48000, int, section="df")
161
+ logger.info(f"Got parameters speech_upl: {speech_upl}, noise: {noise_type}, snr: {snr}, atten_lim_db: {atten_lim_db}, wet_dry_mix: {wet_dry_mix}, post_process: {post_process}")
162
  snr = int(snr)
163
  noise_fn = NOISES[noise_type]
164
  meta = AudioMetaData(-1, -1, -1, -1, "")
 
204
  alpha = wet_dry_mix / 100.0
205
  enhanced = alpha * enhanced + (1 - alpha) * sample
206
 
207
+ # Apply professional post-processing (Low-cut filter + presence boost EQ)
208
  if post_process:
209
+ enhanced = post_process_audio(enhanced, sr)
210
 
211
  lim = torch.linspace(0.0, 1.0, int(sr * 0.15)).unsqueeze(0)
212
  lim = torch.cat((lim, torch.ones(1, enhanced.shape[-1] - lim.shape[1])), dim=1)
 
374
  mic_input = gr.Mic(label="Input", type="filepath", visible=False)
375
  audio_file = gr.Audio(type="filepath", label="Input", visible=True)
376
  inputs = [
 
377
  audio_file,
378
  gr.Dropdown(
379
  label="Add background noise",
 
400
  label="Voice Naturalness Mix (%) - 100% is fully denoised, 90% blends back some original voice",
401
  ),
402
  gr.Checkbox(
403
+ label="Post-Process (80Hz Low-Cut & Presence Boost)",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  value=True,
405
  ),
406
  mic_input,
 
419
  radio.change(toggle, radio, [mic_input, audio_file])
420
  gr.Examples(
421
  [
422
+ ["./samples/p232_013_clean.wav", "Kitchen", "10", 15, 90, True, None],
423
+ ["./samples/p232_013_clean.wav", "Cafe", "10", 15, 90, True, None],
424
+ ["./samples/p232_019_clean.wav", "Cafe", "10", 15, 90, True, None],
425
+ ["./samples/p232_019_clean.wav", "River", "10", 15, 90, True, None],
426
  ],
427
  fn=demo_fn,
428
  inputs=inputs,