ongudidan commited on
Commit
fb3ee9b
·
1 Parent(s): eff59b0

feat: add adjustable low-cut, bass, and treble controls to post-processing and revamp Gradio UI

Browse files
Files changed (1) hide show
  1. app.py +130 -51
app.py CHANGED
@@ -129,15 +129,27 @@ def ensure_wav(filepath: str) -> str:
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,19 +158,23 @@ def post_process_audio(waveform: Tensor, sr: int) -> Tensor:
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,9 +220,9 @@ def demo_fn(
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)
@@ -357,78 +373,141 @@ def toggle(choice):
357
  return gr.update(visible=False, value=None), gr.update(visible=True, value=None)
358
 
359
 
360
- with gr.Blocks() as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  with gr.Row():
362
  gr.Markdown(
363
  """
364
- ## DeepFilterNet2 Demo\
365
-
366
- This demo denoises audio files using DeepFilterNet. Try it with your own voice!
367
  """
368
  )
369
  with gr.Row():
370
  with gr.Column():
 
371
  radio = gr.Radio(
372
- ["mic", "file"], value="file", label="How would you like to upload your audio?"
373
  )
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",
 
380
  choices=list(NOISES.keys()),
381
  value="None",
382
- ),
383
- gr.Dropdown(
384
- label="Noise Level (SNR)",
385
  choices=["-5", "0", "10", "20"],
386
  value="10",
387
- ),
388
- gr.Slider(
 
 
 
389
  minimum=6,
390
  maximum=35,
391
  step=1,
392
  value=15,
393
- label="Max Attenuation (dB) - lower is more natural/clear, higher reduces more noise",
394
- ),
395
- gr.Slider(
396
  minimum=50,
397
  maximum=100,
398
  step=5,
399
  value=90,
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,
407
  ]
408
- btn = gr.Button("Generate")
409
  with gr.Column():
 
410
  outputs = [
411
- # gr.Video(type="filepath", label="Noisy audio"),
412
- gr.Audio(type="filepath", label="Noisy audio"),
413
- gr.Image(label="Noisy spectrogram"),
414
- # gr.Video(type="filepath", label="Enhanced audio"),
415
- gr.Audio(type="filepath", label="Enhanced audio"),
416
- gr.Image(label="Enhanced spectrogram"),
417
  ]
418
  btn.click(fn=demo_fn, inputs=inputs, outputs=outputs, api_name='denoise')
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,
429
- outputs=outputs,
430
- cache_examples=True,
431
- ),
432
  gr.Markdown(open("usage.md").read())
433
 
434
  cleanup_tmp()
 
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
+ ) -> Tensor:
139
  """Apply professional DSP filters to make voice audio crisp and clear."""
140
+ # 1. High-pass filter (Low-cut) to cut sub-bass rumble and AC hums
141
+ if low_cut_freq > 20:
142
+ waveform = F_audio.highpass_biquad(waveform, sample_rate=sr, cutoff_freq=low_cut_freq)
143
 
144
+ # 2. Bass EQ peaking filter at 150 Hz to add warmth or reduce muddiness
145
+ if bass_gain != 0:
146
+ waveform = F_audio.equalizer_biquad(waveform, sample_rate=sr, center_freq=150.0, gain=bass_gain, Q=0.707)
147
 
148
+ # 3. Treble EQ peaking filter at 6000 Hz to add air, presence, and vocal crispness
149
+ if treble_gain != 0:
150
+ waveform = F_audio.equalizer_biquad(waveform, sample_rate=sr, center_freq=6000.0, gain=treble_gain, Q=0.707)
151
+
152
+ # 4. Normalize peak to -1.0 dBFS (0.9 max amplitude) to maximize volume without clipping
153
  max_val = waveform.abs().max()
154
  if max_val > 0:
155
  waveform = waveform * (0.9 / max_val)
 
158
 
159
 
160
  def demo_fn(
161
+ input_type: str,
162
  speech_upl: str,
163
  noise_type: str,
164
  snr: int,
165
  atten_lim_db: float,
166
  wet_dry_mix: float,
167
  post_process: bool,
168
+ low_cut_freq: float,
169
+ bass_gain: float,
170
+ treble_gain: float,
171
  mic_input: Optional[str] = None,
172
  ):
173
+ if input_type == "mic":
174
  speech_upl = mic_input
175
 
176
  sr = config("sr", 48000, int, section="df")
177
+ 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}")
178
  snr = int(snr)
179
  noise_fn = NOISES[noise_type]
180
  meta = AudioMetaData(-1, -1, -1, -1, "")
 
220
  alpha = wet_dry_mix / 100.0
221
  enhanced = alpha * enhanced + (1 - alpha) * sample
222
 
223
+ # Apply professional post-processing (Low-cut filter + bass EQ + treble EQ)
224
  if post_process:
225
+ enhanced = post_process_audio(enhanced, sr, low_cut_freq, bass_gain, treble_gain)
226
 
227
  lim = torch.linspace(0.0, 1.0, int(sr * 0.15)).unsqueeze(0)
228
  lim = torch.cat((lim, torch.ones(1, enhanced.shape[-1] - lim.shape[1])), dim=1)
 
373
  return gr.update(visible=False, value=None), gr.update(visible=True, value=None)
374
 
375
 
376
+ theme = gr.themes.Soft(
377
+ primary_hue="blue",
378
+ secondary_hue="indigo",
379
+ neutral_hue="slate",
380
+ font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "sans-serif"],
381
+ )
382
+
383
+ css = """
384
+ .gradio-container {
385
+ max-width: 1150px !important;
386
+ }
387
+ .generate-btn {
388
+ background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%) !important;
389
+ color: white !important;
390
+ border: none !important;
391
+ font-weight: 600 !important;
392
+ transition: all 0.2s ease-in-out !important;
393
+ box-shadow: 0 4px 6px -1px rgba(37, 99, 235, 0.2) !important;
394
+ }
395
+ .generate-btn:hover {
396
+ background: linear-gradient(135deg, #1d4ed8 0%, #1e40af 100%) !important;
397
+ transform: translateY(-1px) !important;
398
+ box-shadow: 0 6px 15px rgba(37, 99, 235, 0.35) !important;
399
+ }
400
+ """
401
+
402
+ with gr.Blocks(theme=theme, css=css) as demo:
403
  with gr.Row():
404
  gr.Markdown(
405
  """
406
+ # 🎙️ DeepFilterNet Audio Studio
407
+ Enhance voice recordings using **DeepFilterNet2** — an ultra-fast, real-time speech enhancement model.
408
+ Adjust settings below to clean up background noise and customize vocal EQ characteristics.
409
  """
410
  )
411
  with gr.Row():
412
  with gr.Column():
413
+ gr.Markdown("### 📂 1. Audio Source")
414
  radio = gr.Radio(
415
+ ["mic", "file"], value="file", label="Input Method"
416
  )
417
+ mic_input = gr.Mic(label="Record Voice", type="filepath", visible=False)
418
+ audio_file = gr.Audio(type="filepath", label="Upload Audio File", visible=True)
419
+
420
+ gr.Markdown("### 🔊 2. Noise Simulation (Optional)")
421
+ with gr.Group():
422
+ noise_select = gr.Dropdown(
423
+ label="Add Background Noise",
424
  choices=list(NOISES.keys()),
425
  value="None",
426
+ )
427
+ snr_select = gr.Dropdown(
428
+ label="Simulated Noise Level (SNR)",
429
  choices=["-5", "0", "10", "20"],
430
  value="10",
431
+ )
432
+
433
+ gr.Markdown("### ⚙️ 3. Denoising Settings")
434
+ with gr.Group():
435
+ atten_slider = gr.Slider(
436
  minimum=6,
437
  maximum=35,
438
  step=1,
439
  value=15,
440
+ label="Max Attenuation (dB) - lower keeps natural room tone, higher reduces more noise",
441
+ )
442
+ blend_slider = gr.Slider(
443
  minimum=50,
444
  maximum=100,
445
  step=5,
446
  value=90,
447
+ label="Voice Naturalness Mix (%) - blends original signal back to preserve transients",
448
+ )
449
+
450
+ with gr.Accordion("🎨 4. Advanced Vocal EQ & Presence", open=False):
451
+ post_process_cb = gr.Checkbox(
452
+ label="Enable Post-Processing EQ & Filters",
453
  value=True,
454
+ )
455
+ low_cut_slider = gr.Slider(
456
+ minimum=20,
457
+ maximum=200,
458
+ step=10,
459
+ value=80,
460
+ label="Low-Cut Filter Cutoff (Hz) - removes sub-bass rumble/AC hum",
461
+ )
462
+ bass_slider = gr.Slider(
463
+ minimum=-10,
464
+ maximum=10,
465
+ step=1,
466
+ value=0,
467
+ label="Voice Bass Boost (dB) at 150Hz - adds body/warmth to thin voices",
468
+ )
469
+ treble_slider = gr.Slider(
470
+ minimum=-10,
471
+ maximum=10,
472
+ step=1,
473
+ value=3,
474
+ label="Voice Treble Boost (dB) at 6kHz - adds sibilance/crispness",
475
+ )
476
+
477
+ inputs = [
478
+ radio,
479
+ audio_file,
480
+ noise_select,
481
+ snr_select,
482
+ atten_slider,
483
+ blend_slider,
484
+ post_process_cb,
485
+ low_cut_slider,
486
+ bass_slider,
487
+ treble_slider,
488
  mic_input,
489
  ]
490
+ btn = gr.Button("Generate Denoised Audio", elem_classes="generate-btn")
491
  with gr.Column():
492
+ gr.Markdown("### 📊 Results & Visualization")
493
  outputs = [
494
+ gr.Audio(type="filepath", label="Noisy Audio (Input)"),
495
+ gr.Image(label="Noisy Spectrogram"),
496
+ gr.Audio(type="filepath", label="Enhanced Audio (Output)"),
497
+ gr.Image(label="Enhanced Spectrogram"),
 
 
498
  ]
499
  btn.click(fn=demo_fn, inputs=inputs, outputs=outputs, api_name='denoise')
500
  radio.change(toggle, radio, [mic_input, audio_file])
501
  gr.Examples(
502
+ examples=[
503
+ ["./samples/p232_013_clean.wav", "Kitchen", "10"],
504
+ ["./samples/p232_013_clean.wav", "Cafe", "10"],
505
+ ["./samples/p232_019_clean.wav", "Cafe", "10"],
506
+ ["./samples/p232_019_clean.wav", "River", "10"],
507
  ],
508
+ inputs=[audio_file, noise_select, snr_select],
509
+ label="💡 Quick Start Demo Examples (Click to load)",
510
+ )
 
 
511
  gr.Markdown(open("usage.md").read())
512
 
513
  cleanup_tmp()