Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -134,17 +134,28 @@ def match_loudness(audio_path, target_lufs=-14.0):
|
|
| 134 |
adjusted.export(out_path, format="wav")
|
| 135 |
return out_path
|
| 136 |
|
| 137 |
-
# === Auto-EQ per Genre ===
|
| 138 |
def auto_eq(audio, genre="Pop"):
|
| 139 |
eq_map = {
|
| 140 |
-
"Pop": [(200, 500, -3), (2000, 4000, +4)],
|
| 141 |
-
"EDM": [(60, 250, +6), (8000, 12000, +3)],
|
| 142 |
-
"Rock": [(1000, 3000, +4), (7000, 10000, -3)],
|
| 143 |
-
"Hip-Hop": [(20, 100, +6), (7000, 10000, -4)],
|
| 144 |
-
"Acoustic": [(100, 300, -3), (4000, 8000, +2)],
|
| 145 |
-
"Metal": [(100, 500, -4), (2000, 5000, +6), (7000, 12000, -3)],
|
| 146 |
-
"Trap": [(80, 120, +6), (3000, 6000, -4)],
|
| 147 |
-
"LoFi": [(20, 200, +3), (1000, 3000, -2)],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
"Default": []
|
| 149 |
}
|
| 150 |
|
|
@@ -185,7 +196,7 @@ def ai_mastering_chain(audio_path, genre="Pop", target_lufs=-14.0):
|
|
| 185 |
final_audio.export(out_path, format="wav")
|
| 186 |
return out_path
|
| 187 |
|
| 188 |
-
# === Harmonic Saturation / Exciter β Now
|
| 189 |
def harmonic_saturation(audio, saturation_type="Tube", intensity=0.2):
|
| 190 |
samples = np.array(audio.get_array_of_samples()).astype(np.float32)
|
| 191 |
|
|
@@ -335,7 +346,7 @@ def generate_session_log(audio_path, effects, isolate_vocals, export_format, gen
|
|
| 335 |
}
|
| 336 |
return json.dumps(log, indent=2)
|
| 337 |
|
| 338 |
-
# === Load Presets ===
|
| 339 |
preset_choices = {
|
| 340 |
"Default": [],
|
| 341 |
"Clean Podcast": ["Noise Reduction", "Normalize"],
|
|
@@ -350,7 +361,18 @@ preset_choices = {
|
|
| 350 |
"πΆ Singer's Harmony": ["Harmony", "Stereo Widening", "Pitch Shift"],
|
| 351 |
"π« ASMR Vocal": ["Auto Gain", "Low-Pass Filter (3000Hz)", "Noise Gate"],
|
| 352 |
"πΌ Stage Mode": ["Reverb", "Bass Boost", "Limiter"],
|
| 353 |
-
"π΅ Auto-Tune Style": ["Pitch Shift (+1 semitone)", "Normalize", "Treble Boost"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 354 |
}
|
| 355 |
|
| 356 |
preset_names = list(preset_choices.keys())
|
|
@@ -391,7 +413,6 @@ def auto_tune_vocal(audio_path, target_key="C"):
|
|
| 391 |
def visualize_spectrum(audio_path):
|
| 392 |
y, sr = torchaudio.load(audio_path)
|
| 393 |
y_np = y.numpy().flatten()
|
| 394 |
-
|
| 395 |
stft = librosa.stft(y_np)
|
| 396 |
db = librosa.amplitude_to_db(abs(stft))
|
| 397 |
|
|
@@ -439,7 +460,10 @@ with gr.Blocks(title="AI Audio Studio", css="style.css") as demo:
|
|
| 439 |
fn=ai_mastering_chain,
|
| 440 |
inputs=[
|
| 441 |
gr.Audio(label="Upload Track", type="filepath"),
|
| 442 |
-
gr.Dropdown(choices=["Pop", "EDM", "Rock", "Hip-Hop", "Acoustic", "Metal", "Trap", "LoFi"
|
|
|
|
|
|
|
|
|
|
| 443 |
gr.Slider(minimum=-24, maximum=-6, value=-14, label="Target LUFS")
|
| 444 |
],
|
| 445 |
outputs=gr.Audio(label="Mastered Output", type="filepath"),
|
|
@@ -479,7 +503,7 @@ with gr.Blocks(title="AI Audio Studio", css="style.css") as demo:
|
|
| 479 |
description="Enhance clarity and presence using saturation styles like Tube or Tape."
|
| 480 |
)
|
| 481 |
|
| 482 |
-
# --- Vocal Doubler / Harmonizer ===
|
| 483 |
with gr.Tab("π§ Vocal Doubler / Harmonizer"):
|
| 484 |
gr.Interface(
|
| 485 |
fn=lambda x: apply_harmony(x),
|
|
@@ -562,7 +586,16 @@ with gr.Blocks(title="AI Audio Studio", css="style.css") as demo:
|
|
| 562 |
def load_project(project_file):
|
| 563 |
with open(project_file.name, "rb") as f:
|
| 564 |
data = pickle.load(f)
|
| 565 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 566 |
|
| 567 |
with gr.Tab("π Save/Load Project"):
|
| 568 |
gr.Interface(
|
|
@@ -574,14 +607,21 @@ with gr.Blocks(title="AI Audio Studio", css="style.css") as demo:
|
|
| 574 |
],
|
| 575 |
outputs=gr.File(label="Project File (.aiproj)"),
|
| 576 |
title="Save Everything Together",
|
| 577 |
-
description="Save your session, effects, and settings in one file to reuse later."
|
|
|
|
| 578 |
)
|
| 579 |
|
| 580 |
gr.Interface(
|
| 581 |
fn=load_project,
|
| 582 |
inputs=gr.File(label="Upload .aiproj File"),
|
| 583 |
outputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
| 584 |
gr.Dropdown(choices=preset_names, label="Loaded Preset"),
|
|
|
|
|
|
|
| 585 |
gr.CheckboxGroup(choices=preset_choices["Default"], label="Loaded Effects")
|
| 586 |
],
|
| 587 |
title="Resume Last Project",
|
|
@@ -599,16 +639,24 @@ with gr.Blocks(title="AI Audio Studio", css="style.css") as demo:
|
|
| 599 |
("images/acoustic_card.png", "Acoustic"),
|
| 600 |
("images/stage_mode_card.png", "Stage Mode"),
|
| 601 |
("images/vocal_distortion_card.png", "Vocal Distortion"),
|
| 602 |
-
("images/tube_saturation_card.png", "Tube Saturation")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 603 |
], label="Preset Cards", columns=4, height="auto")
|
| 604 |
|
| 605 |
preset_name_out = gr.Dropdown(choices=preset_names, label="Selected Preset")
|
| 606 |
-
preset_effects_out = gr.CheckboxGroup(choices=list(preset_choices[
|
| 607 |
|
| 608 |
def load_preset_by_card(evt: gr.SelectData):
|
| 609 |
index = evt.index % len(preset_names)
|
| 610 |
name = preset_names[index]
|
| 611 |
-
|
|
|
|
| 612 |
|
| 613 |
preset_gallery.select(fn=load_preset_by_card, inputs=[], outputs=[preset_name_out, preset_effects_out])
|
| 614 |
|
|
|
|
| 134 |
adjusted.export(out_path, format="wav")
|
| 135 |
return out_path
|
| 136 |
|
| 137 |
+
# === Auto-EQ per Genre β With New Genres Added ===
|
| 138 |
def auto_eq(audio, genre="Pop"):
|
| 139 |
eq_map = {
|
| 140 |
+
"Pop": [(200, 500, -3), (2000, 4000, +4)], # Cut muddiness, boost vocals
|
| 141 |
+
"EDM": [(60, 250, +6), (8000, 12000, +3)], # Maximize bass & sparkle
|
| 142 |
+
"Rock": [(1000, 3000, +4), (7000, 10000, -3)], # Punchy mids, reduce sibilance
|
| 143 |
+
"Hip-Hop": [(20, 100, +6), (7000, 10000, -4)], # Deep lows, smooth highs
|
| 144 |
+
"Acoustic": [(100, 300, -3), (4000, 8000, +2)], # Natural tone
|
| 145 |
+
"Metal": [(100, 500, -4), (2000, 5000, +6), (7000, 12000, -3)], # Clear low-mids, crisp highs
|
| 146 |
+
"Trap": [(80, 120, +6), (3000, 6000, -4)], # Sub-bass boost, cut harsh highs
|
| 147 |
+
"LoFi": [(20, 200, +3), (1000, 3000, -2)], # Warmth, soft mids
|
| 148 |
+
"Jazz": [(100, 400, +2), (1500, 3000, +1)], # Smooth midrange
|
| 149 |
+
"Classical": [(200, 1000, +1), (3000, 6000, +2)], # Balanced orchestral EQ
|
| 150 |
+
"Chillhop": [(50, 200, +3), (2000, 5000, +1)], # Laid-back warmth
|
| 151 |
+
"Ambient": [(100, 500, +4), (6000, 12000, +2)], # Spacey atmosphere
|
| 152 |
+
"Jazz Piano": [(100, 1000, +3), (2000, 5000, +2)], # Rich piano tone
|
| 153 |
+
"Trap EDM": [(60, 120, +6), (2000, 5000, -3)], # Heavy sub + clean highs
|
| 154 |
+
"Indie Rock": [(150, 400, +2), (2000, 5000, +3)], # Crisp guitars
|
| 155 |
+
"Lo-Fi Jazz": [(80, 200, +3), (2000, 4000, +1)], # Cozy jazz warmth
|
| 156 |
+
"R&B": [(100, 300, +4), (2000, 4000, +3)], # Full vocals
|
| 157 |
+
"Soul": [(80, 200, +3), (1500, 3500, +4)], # Emotive vocal clarity
|
| 158 |
+
"Funk": [(80, 200, +5), (1000, 3000, +3)], # Tight low end
|
| 159 |
"Default": []
|
| 160 |
}
|
| 161 |
|
|
|
|
| 196 |
final_audio.export(out_path, format="wav")
|
| 197 |
return out_path
|
| 198 |
|
| 199 |
+
# === Harmonic Saturation / Exciter β Now Defined Before Use ===
|
| 200 |
def harmonic_saturation(audio, saturation_type="Tube", intensity=0.2):
|
| 201 |
samples = np.array(audio.get_array_of_samples()).astype(np.float32)
|
| 202 |
|
|
|
|
| 346 |
}
|
| 347 |
return json.dumps(log, indent=2)
|
| 348 |
|
| 349 |
+
# === Load Presets β With Missing Genres Added Back ===
|
| 350 |
preset_choices = {
|
| 351 |
"Default": [],
|
| 352 |
"Clean Podcast": ["Noise Reduction", "Normalize"],
|
|
|
|
| 361 |
"πΆ Singer's Harmony": ["Harmony", "Stereo Widening", "Pitch Shift"],
|
| 362 |
"π« ASMR Vocal": ["Auto Gain", "Low-Pass Filter (3000Hz)", "Noise Gate"],
|
| 363 |
"πΌ Stage Mode": ["Reverb", "Bass Boost", "Limiter"],
|
| 364 |
+
"π΅ Auto-Tune Style": ["Pitch Shift (+1 semitone)", "Normalize", "Treble Boost"],
|
| 365 |
+
"π· Jazz Vocal": ["Bass Boost (-200-400Hz)", "Treble Boost (2000-4000Hz)", "Normalize"],
|
| 366 |
+
"πΉ Jazz Piano": ["Treble Boost (4000-6000Hz)", "Normalize", "Stereo Widening"],
|
| 367 |
+
"π» Classical Strings": ["Bass Boost (100-500Hz)", "Treble Boost (3000-6000Hz)", "Reverb"],
|
| 368 |
+
"β Chillhop": ["Noise Gate", "Treble Boost (-3000Hz)", "Reverb"],
|
| 369 |
+
"π Ambient": ["Reverb", "Noise Gate", "Treble Boost (6000-12000Hz)"],
|
| 370 |
+
"π€ R&B Vocal": ["Noise Reduction", "Bass Boost (100-300Hz)", "Treble Boost (2000-4000Hz)"],
|
| 371 |
+
"π Soul Vocal": ["Noise Reduction", "Bass Boost (80-200Hz)", "Treble Boost (1500-3500Hz)"],
|
| 372 |
+
"πΊ Funk Groove": ["Bass Boost (80-200Hz)", "Treble Boost (1000-3000Hz)", "Stereo Widening"],
|
| 373 |
+
"πΉ Jazz Piano Solo": ["Treble Boost (2000-5000Hz)", "Normalize", "Stage Mode"],
|
| 374 |
+
"πΆ Trap EDM": ["Bass Boost (60-120Hz)", "Treble Boost (2000-5000Hz)", "Limiter"],
|
| 375 |
+
"πΈ Indie Rock": ["Bass Boost (150-400Hz)", "Treble Boost (2000-5000Hz)", "Compress Dynamic Range"]
|
| 376 |
}
|
| 377 |
|
| 378 |
preset_names = list(preset_choices.keys())
|
|
|
|
| 413 |
def visualize_spectrum(audio_path):
|
| 414 |
y, sr = torchaudio.load(audio_path)
|
| 415 |
y_np = y.numpy().flatten()
|
|
|
|
| 416 |
stft = librosa.stft(y_np)
|
| 417 |
db = librosa.amplitude_to_db(abs(stft))
|
| 418 |
|
|
|
|
| 460 |
fn=ai_mastering_chain,
|
| 461 |
inputs=[
|
| 462 |
gr.Audio(label="Upload Track", type="filepath"),
|
| 463 |
+
gr.Dropdown(choices=["Pop", "EDM", "Rock", "Hip-Hop", "Acoustic", "Metal", "Trap", "LoFi",
|
| 464 |
+
"Jazz", "Classical", "Chillhop", "Ambient", "Jazz Piano", "Trap EDM",
|
| 465 |
+
"Indie Rock", "Lo-Fi Jazz", "R&B", "Soul", "Funk"],
|
| 466 |
+
label="Genre", value="Pop"),
|
| 467 |
gr.Slider(minimum=-24, maximum=-6, value=-14, label="Target LUFS")
|
| 468 |
],
|
| 469 |
outputs=gr.Audio(label="Mastered Output", type="filepath"),
|
|
|
|
| 503 |
description="Enhance clarity and presence using saturation styles like Tube or Tape."
|
| 504 |
)
|
| 505 |
|
| 506 |
+
# --- Vocal Doubler / Harmonizer β Added ===
|
| 507 |
with gr.Tab("π§ Vocal Doubler / Harmonizer"):
|
| 508 |
gr.Interface(
|
| 509 |
fn=lambda x: apply_harmony(x),
|
|
|
|
| 586 |
def load_project(project_file):
|
| 587 |
with open(project_file.name, "rb") as f:
|
| 588 |
data = pickle.load(f)
|
| 589 |
+
return (
|
| 590 |
+
array_to_audiosegment(data["audio"], 44100),
|
| 591 |
+
array_to_audiosegment(data["audio"], 44100),
|
| 592 |
+
array_to_audiosegment(data["audio"], 44100),
|
| 593 |
+
array_to_audiosegment(data["audio"], 44100),
|
| 594 |
+
data["preset"],
|
| 595 |
+
data["effects"],
|
| 596 |
+
data["effects"],
|
| 597 |
+
data["effects"]
|
| 598 |
+
)
|
| 599 |
|
| 600 |
with gr.Tab("π Save/Load Project"):
|
| 601 |
gr.Interface(
|
|
|
|
| 607 |
],
|
| 608 |
outputs=gr.File(label="Project File (.aiproj)"),
|
| 609 |
title="Save Everything Together",
|
| 610 |
+
description="Save your session, effects, and settings in one file to reuse later.",
|
| 611 |
+
allow_flagging="never"
|
| 612 |
)
|
| 613 |
|
| 614 |
gr.Interface(
|
| 615 |
fn=load_project,
|
| 616 |
inputs=gr.File(label="Upload .aiproj File"),
|
| 617 |
outputs=[
|
| 618 |
+
gr.File(label="Loaded Vocals"),
|
| 619 |
+
gr.File(label="Loaded Drums"),
|
| 620 |
+
gr.File(label="Loaded Bass"),
|
| 621 |
+
gr.File(label="Loaded Other"),
|
| 622 |
gr.Dropdown(choices=preset_names, label="Loaded Preset"),
|
| 623 |
+
gr.CheckboxGroup(choices=preset_choices["Default"], label="Loaded Effects"),
|
| 624 |
+
gr.CheckboxGroup(choices=preset_choices["Default"], label="Loaded Effects"),
|
| 625 |
gr.CheckboxGroup(choices=preset_choices["Default"], label="Loaded Effects")
|
| 626 |
],
|
| 627 |
title="Resume Last Project",
|
|
|
|
| 639 |
("images/acoustic_card.png", "Acoustic"),
|
| 640 |
("images/stage_mode_card.png", "Stage Mode"),
|
| 641 |
("images/vocal_distortion_card.png", "Vocal Distortion"),
|
| 642 |
+
("images/tube_saturation_card.png", "Tube Saturation"),
|
| 643 |
+
("images/jazz_card.png", "Jazz"),
|
| 644 |
+
("images/classical_card.png", "Classical"),
|
| 645 |
+
("images/chillhop_card.png", "Chillhop"),
|
| 646 |
+
("images/ambient_card.png", "Ambient"),
|
| 647 |
+
("images/rnb_card.png", "R&B"),
|
| 648 |
+
("images/soul_card.png", "Soul"),
|
| 649 |
+
("images/funk_card.png", "Funk")
|
| 650 |
], label="Preset Cards", columns=4, height="auto")
|
| 651 |
|
| 652 |
preset_name_out = gr.Dropdown(choices=preset_names, label="Selected Preset")
|
| 653 |
+
preset_effects_out = gr.CheckboxGroup(choices=list(preset_choices.keys())[0:], label="Effects")
|
| 654 |
|
| 655 |
def load_preset_by_card(evt: gr.SelectData):
|
| 656 |
index = evt.index % len(preset_names)
|
| 657 |
name = preset_names[index]
|
| 658 |
+
effects = preset_choices[name]
|
| 659 |
+
return name, effects
|
| 660 |
|
| 661 |
preset_gallery.select(fn=load_preset_by_card, inputs=[], outputs=[preset_name_out, preset_effects_out])
|
| 662 |
|