Spaces:
Sleeping
Sleeping
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 |
|