Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -21,6 +21,7 @@ from faster_whisper import WhisperModel
|
|
| 21 |
from TTS.api import TTS
|
| 22 |
import base64
|
| 23 |
import pickle
|
|
|
|
| 24 |
|
| 25 |
# Suppress warnings
|
| 26 |
warnings.filterwarnings("ignore")
|
|
@@ -157,6 +158,29 @@ def auto_eq(audio, genre="Pop"):
|
|
| 157 |
|
| 158 |
return array_to_audiosegment(samples.astype(np.int16), sr, channels=audio.channels)
|
| 159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
# === Vocal Isolation Helpers ===
|
| 161 |
def load_track_local(path, sample_rate, channels=2):
|
| 162 |
sig, rate = torchaudio.load(path)
|
|
@@ -255,7 +279,7 @@ def process_audio(audio_file, selected_effects, isolate_vocals, preset_name, exp
|
|
| 255 |
status = f"β Error: {str(e)}"
|
| 256 |
return None, None, status, "", status
|
| 257 |
|
| 258 |
-
# ===
|
| 259 |
def show_waveform(audio_file):
|
| 260 |
try:
|
| 261 |
audio = AudioSegment.from_file(audio_file)
|
|
@@ -323,7 +347,7 @@ def batch_process_audio(files, selected_effects, isolate_vocals, preset_name, ex
|
|
| 323 |
results.append(processed_path)
|
| 324 |
session_logs.append(log)
|
| 325 |
|
| 326 |
-
zip_path = os.path.join(
|
| 327 |
with zipfile.ZipFile(zip_path, 'w') as zipf:
|
| 328 |
for i, res in enumerate(results):
|
| 329 |
filename = f"processed_{i}.{export_format.lower()}"
|
|
@@ -347,6 +371,7 @@ def auto_tune_vocal(audio_path, target_key="C"):
|
|
| 347 |
def visualize_spectrum(audio_path):
|
| 348 |
y, sr = torchaudio.load(audio_path)
|
| 349 |
y_np = y.numpy().flatten()
|
|
|
|
| 350 |
stft = librosa.stft(y_np)
|
| 351 |
db = librosa.amplitude_to_db(abs(stft))
|
| 352 |
|
|
@@ -388,6 +413,21 @@ with gr.Blocks(title="AI Audio Studio", css="style.css") as demo:
|
|
| 388 |
output_audio, waveform_img, session_log_out, genre_out, status_box
|
| 389 |
])
|
| 390 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 391 |
# --- Remix Mode ---
|
| 392 |
with gr.Tab("π Remix Mode"):
|
| 393 |
gr.Interface(
|
|
@@ -405,21 +445,6 @@ with gr.Blocks(title="AI Audio Studio", css="style.css") as demo:
|
|
| 405 |
clear_btn=None
|
| 406 |
)
|
| 407 |
|
| 408 |
-
# --- AI Mastering Chain Tab ===
|
| 409 |
-
with gr.Tab("π§ AI Mastering Chain"):
|
| 410 |
-
gr.Interface(
|
| 411 |
-
fn=ai_mastering_chain,
|
| 412 |
-
inputs=[
|
| 413 |
-
gr.Audio(label="Upload Track", type="filepath"),
|
| 414 |
-
gr.Dropdown(choices=["Pop", "EDM", "Rock", "Hip-Hop", "Acoustic", "Metal", "Trap", "LoFi"], label="Genre", value="Pop"),
|
| 415 |
-
gr.Slider(minimum=-24, maximum=-6, value=-14, label="Target LUFS")
|
| 416 |
-
],
|
| 417 |
-
outputs=gr.Audio(label="Mastered Output", type="filepath"),
|
| 418 |
-
title="Genre-Based Mastering",
|
| 419 |
-
description="Apply genre-specific EQ + loudness matching + limiter",
|
| 420 |
-
allow_flagging="never"
|
| 421 |
-
)
|
| 422 |
-
|
| 423 |
# --- Harmonic Saturation / Exciter ===
|
| 424 |
with gr.Tab("𧬠Harmonic Saturation"):
|
| 425 |
gr.Interface(
|
|
|
|
| 21 |
from TTS.api import TTS
|
| 22 |
import base64
|
| 23 |
import pickle
|
| 24 |
+
import json
|
| 25 |
|
| 26 |
# Suppress warnings
|
| 27 |
warnings.filterwarnings("ignore")
|
|
|
|
| 158 |
|
| 159 |
return array_to_audiosegment(samples.astype(np.int16), sr, channels=audio.channels)
|
| 160 |
|
| 161 |
+
# === AI Mastering Chain β Genre EQ + Loudness Match + Limiting ===
|
| 162 |
+
def ai_mastering_chain(audio_path, genre="Pop", target_lufs=-14.0):
|
| 163 |
+
audio = AudioSegment.from_file(audio_path)
|
| 164 |
+
|
| 165 |
+
# Apply Genre EQ
|
| 166 |
+
eq_audio = auto_eq(audio, genre=genre)
|
| 167 |
+
|
| 168 |
+
# Convert to numpy for loudness
|
| 169 |
+
samples, sr = audiosegment_to_array(eq_audio)
|
| 170 |
+
|
| 171 |
+
# Apply loudness normalization
|
| 172 |
+
meter = pyln.Meter(sr)
|
| 173 |
+
loudness = meter.integrated_loudness(samples.astype(np.float64) / 32768.0)
|
| 174 |
+
gain_db = target_lufs - loudness
|
| 175 |
+
final_audio = eq_audio + gain_db
|
| 176 |
+
|
| 177 |
+
# Final limiting
|
| 178 |
+
final_audio = apply_limiter(final_audio)
|
| 179 |
+
|
| 180 |
+
out_path = os.path.join(tempfile.gettempdir(), "mastered_output.wav")
|
| 181 |
+
final_audio.export(out_path, format="wav")
|
| 182 |
+
return out_path
|
| 183 |
+
|
| 184 |
# === Vocal Isolation Helpers ===
|
| 185 |
def load_track_local(path, sample_rate, channels=2):
|
| 186 |
sig, rate = torchaudio.load(path)
|
|
|
|
| 279 |
status = f"β Error: {str(e)}"
|
| 280 |
return None, None, status, "", status
|
| 281 |
|
| 282 |
+
# === Waveform + Spectrogram Generator ===
|
| 283 |
def show_waveform(audio_file):
|
| 284 |
try:
|
| 285 |
audio = AudioSegment.from_file(audio_file)
|
|
|
|
| 347 |
results.append(processed_path)
|
| 348 |
session_logs.append(log)
|
| 349 |
|
| 350 |
+
zip_path = os.path.join(tempfile.gettempdir(), "batch_output.zip")
|
| 351 |
with zipfile.ZipFile(zip_path, 'w') as zipf:
|
| 352 |
for i, res in enumerate(results):
|
| 353 |
filename = f"processed_{i}.{export_format.lower()}"
|
|
|
|
| 371 |
def visualize_spectrum(audio_path):
|
| 372 |
y, sr = torchaudio.load(audio_path)
|
| 373 |
y_np = y.numpy().flatten()
|
| 374 |
+
|
| 375 |
stft = librosa.stft(y_np)
|
| 376 |
db = librosa.amplitude_to_db(abs(stft))
|
| 377 |
|
|
|
|
| 413 |
output_audio, waveform_img, session_log_out, genre_out, status_box
|
| 414 |
])
|
| 415 |
|
| 416 |
+
# --- AI Mastering Chain Tab β Now Fully Defined ===
|
| 417 |
+
with gr.Tab("π§ AI Mastering Chain"):
|
| 418 |
+
gr.Interface(
|
| 419 |
+
fn=ai_mastering_chain,
|
| 420 |
+
inputs=[
|
| 421 |
+
gr.Audio(label="Upload Track", type="filepath"),
|
| 422 |
+
gr.Dropdown(choices=["Pop", "EDM", "Rock", "Hip-Hop", "Acoustic", "Metal", "Trap", "LoFi"], label="Genre", value="Pop"),
|
| 423 |
+
gr.Slider(minimum=-24, maximum=-6, value=-14, label="Target LUFS")
|
| 424 |
+
],
|
| 425 |
+
outputs=gr.Audio(label="Mastered Output", type="filepath"),
|
| 426 |
+
title="Genre-Based Mastering",
|
| 427 |
+
description="Apply genre-specific EQ + loudness matching + limiter",
|
| 428 |
+
allow_flagging="never"
|
| 429 |
+
)
|
| 430 |
+
|
| 431 |
# --- Remix Mode ---
|
| 432 |
with gr.Tab("π Remix Mode"):
|
| 433 |
gr.Interface(
|
|
|
|
| 445 |
clear_btn=None
|
| 446 |
)
|
| 447 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 448 |
# --- Harmonic Saturation / Exciter ===
|
| 449 |
with gr.Tab("𧬠Harmonic Saturation"):
|
| 450 |
gr.Interface(
|