Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -15,6 +15,8 @@ from io import BytesIO
|
|
15 |
from PIL import Image
|
16 |
import zipfile
|
17 |
import datetime
|
|
|
|
|
18 |
|
19 |
# === Helper Functions ===
|
20 |
def audiosegment_to_array(audio):
|
@@ -95,7 +97,7 @@ def apply_vocal_isolation(audio_path):
|
|
95 |
sources = apply_model(model, wav[None])[0]
|
96 |
wav += ref[:, None]
|
97 |
|
98 |
-
vocal_track = sources[3].cpu()
|
99 |
out_path = os.path.join(tempfile.gettempdir(), "vocals.wav")
|
100 |
save_track(out_path, vocal_track, model.samplerate)
|
101 |
return out_path
|
@@ -112,7 +114,7 @@ def stem_split(audio_path):
|
|
112 |
for i, name in enumerate(['drums', 'bass', 'other', 'vocals']):
|
113 |
path = os.path.join(output_dir, f"{name}.wav")
|
114 |
save_track(path, sources[i].cpu(), model.samplerate)
|
115 |
-
stem_paths.append(
|
116 |
|
117 |
return stem_paths
|
118 |
|
@@ -146,21 +148,33 @@ if not preset_choices:
|
|
146 |
|
147 |
preset_names = list(preset_choices.keys())
|
148 |
|
149 |
-
# === Waveform Generator ===
|
150 |
def show_waveform(audio_file):
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
|
165 |
# === Session Info Export ===
|
166 |
def generate_session_log(audio_path, effects, isolate_vocals, export_format):
|
@@ -207,9 +221,10 @@ def process_audio(audio_file, selected_effects, isolate_vocals, preset_name, exp
|
|
207 |
final_audio.export(output_path, format=export_format.lower())
|
208 |
|
209 |
waveform_image = show_waveform(output_path)
|
|
|
210 |
session_log = generate_session_log(audio_file, effects_to_apply, isolate_vocals, export_format)
|
211 |
|
212 |
-
return output_path, waveform_image, session_log
|
213 |
|
214 |
# === Batch Processing Function ===
|
215 |
def batch_process_audio(files, selected_effects, isolate_vocals, preset_name, export_format):
|
@@ -218,7 +233,7 @@ def batch_process_audio(files, selected_effects, isolate_vocals, preset_name, ex
|
|
218 |
session_logs = []
|
219 |
|
220 |
for file in files:
|
221 |
-
processed_path, _, log = process_audio(file.name, selected_effects, isolate_vocals, preset_name, export_format)
|
222 |
results.append(processed_path)
|
223 |
session_logs.append(log)
|
224 |
|
@@ -231,20 +246,7 @@ def batch_process_audio(files, selected_effects, isolate_vocals, preset_name, ex
|
|
231 |
|
232 |
return zip_path
|
233 |
|
234 |
-
# ===
|
235 |
-
def upload_preset(preset_file):
|
236 |
-
try:
|
237 |
-
with open(preset_file.name, "r") as f:
|
238 |
-
data = json.load(f)
|
239 |
-
if "name" in data and "effects" in data:
|
240 |
-
preset_choices[data["name"]] = data["effects"]
|
241 |
-
return f"β
Loaded custom preset: {data['name']}"
|
242 |
-
else:
|
243 |
-
return "β Invalid preset file"
|
244 |
-
except Exception as e:
|
245 |
-
return f"β οΈ Error loading preset: {str(e)}"
|
246 |
-
|
247 |
-
# === Gradio Interface ===
|
248 |
effect_options = [
|
249 |
"Noise Reduction",
|
250 |
"Compress Dynamic Range",
|
@@ -258,8 +260,11 @@ effect_options = [
|
|
258 |
]
|
259 |
|
260 |
# === Multi-Tab UI ===
|
261 |
-
with gr.Blocks(title="AI Audio Studio") as demo:
|
262 |
-
gr.Markdown("
|
|
|
|
|
|
|
263 |
|
264 |
# ----- Single File Studio Tab -----
|
265 |
with gr.Tab("π΅ Single File Studio"):
|
@@ -275,11 +280,14 @@ with gr.Blocks(title="AI Audio Studio") as demo:
|
|
275 |
outputs=[
|
276 |
gr.Audio(label="Processed Audio", type="filepath"),
|
277 |
gr.Image(label="Waveform Preview"),
|
|
|
278 |
gr.Textbox(label="Session Log (JSON)", lines=5)
|
279 |
],
|
280 |
title="Edit One File at a Time",
|
281 |
-
description="Apply effects, preview waveform, and
|
282 |
-
|
|
|
|
|
283 |
)
|
284 |
|
285 |
# ----- Batch Processing Tab -----
|
@@ -296,37 +304,51 @@ with gr.Blocks(title="AI Audio Studio") as demo:
|
|
296 |
outputs=gr.File(label="Download ZIP of All Processed Files"),
|
297 |
title="Batch Audio Processor",
|
298 |
description="Upload multiple files, apply effects in bulk, and download all results in a single ZIP.",
|
299 |
-
flagging_mode="never",
|
300 |
submit_btn="Process All Files",
|
301 |
-
clear_btn=None
|
302 |
)
|
303 |
|
304 |
# ----- Remix Mode Tab -----
|
305 |
with gr.Tab("π Remix Mode (Split Stems)"):
|
306 |
def remix_mode(audio_file):
|
307 |
-
|
308 |
-
return [
|
309 |
-
[name for _, name in stem_paths]
|
310 |
|
311 |
gr.Interface(
|
312 |
fn=remix_mode,
|
313 |
inputs=gr.Audio(label="Upload Music Track", type="filepath"),
|
314 |
outputs=[
|
315 |
-
gr.File(label="
|
316 |
-
gr.
|
|
|
|
|
317 |
],
|
318 |
-
title="Split Into Drums, Bass, Vocals",
|
319 |
-
description="Use AI to separate musical elements like vocals, drums, and bass."
|
|
|
|
|
320 |
)
|
321 |
|
322 |
-
# -----
|
323 |
-
with gr.Tab("
|
|
|
|
|
|
|
324 |
gr.Interface(
|
325 |
-
fn=
|
326 |
-
inputs=
|
327 |
-
|
328 |
-
|
329 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
330 |
)
|
331 |
|
332 |
demo.launch()
|
|
|
15 |
from PIL import Image
|
16 |
import zipfile
|
17 |
import datetime
|
18 |
+
import librosa
|
19 |
+
import librosa.display
|
20 |
|
21 |
# === Helper Functions ===
|
22 |
def audiosegment_to_array(audio):
|
|
|
97 |
sources = apply_model(model, wav[None])[0]
|
98 |
wav += ref[:, None]
|
99 |
|
100 |
+
vocal_track = sources[3].cpu()
|
101 |
out_path = os.path.join(tempfile.gettempdir(), "vocals.wav")
|
102 |
save_track(out_path, vocal_track, model.samplerate)
|
103 |
return out_path
|
|
|
114 |
for i, name in enumerate(['drums', 'bass', 'other', 'vocals']):
|
115 |
path = os.path.join(output_dir, f"{name}.wav")
|
116 |
save_track(path, sources[i].cpu(), model.samplerate)
|
117 |
+
stem_paths.append(path)
|
118 |
|
119 |
return stem_paths
|
120 |
|
|
|
148 |
|
149 |
preset_names = list(preset_choices.keys())
|
150 |
|
151 |
+
# === Waveform + Spectrogram Generator ===
|
152 |
def show_waveform(audio_file):
|
153 |
+
audio = AudioSegment.from_file(audio_file)
|
154 |
+
samples = np.array(audio.get_array_of_samples())
|
155 |
+
plt.figure(figsize=(10, 2))
|
156 |
+
plt.plot(samples[:10000], color="blue")
|
157 |
+
plt.axis("off")
|
158 |
+
buf = BytesIO()
|
159 |
+
plt.savefig(buf, format="png", bbox_inches="tight", dpi=100)
|
160 |
+
plt.close()
|
161 |
+
buf.seek(0)
|
162 |
+
return Image.open(buf)
|
163 |
+
|
164 |
+
def show_spectrogram(audio_file):
|
165 |
+
y, sr = torchaudio.load(audio_file)
|
166 |
+
y_np = y.numpy().flatten()
|
167 |
+
S = librosa.feature.melspectrogram(y=y_np, sr=sr)
|
168 |
+
plt.figure(figsize=(10, 2))
|
169 |
+
librosa.display.specshow(librosa.power_to_db(S, ref=np.max), sr=sr, x_axis='time', y_axis='mel')
|
170 |
+
plt.colorbar(format='%+2.0f dB')
|
171 |
+
plt.title('Spectrogram')
|
172 |
+
plt.tight_layout()
|
173 |
+
buf = BytesIO()
|
174 |
+
plt.savefig(buf, format="png", bbox_inches="tight", dpi=100)
|
175 |
+
plt.close()
|
176 |
+
buf.seek(0)
|
177 |
+
return Image.open(buf)
|
178 |
|
179 |
# === Session Info Export ===
|
180 |
def generate_session_log(audio_path, effects, isolate_vocals, export_format):
|
|
|
221 |
final_audio.export(output_path, format=export_format.lower())
|
222 |
|
223 |
waveform_image = show_waveform(output_path)
|
224 |
+
spectrogram_image = show_spectrogram(output_path)
|
225 |
session_log = generate_session_log(audio_file, effects_to_apply, isolate_vocals, export_format)
|
226 |
|
227 |
+
return output_path, waveform_image, spectrogram_image, session_log
|
228 |
|
229 |
# === Batch Processing Function ===
|
230 |
def batch_process_audio(files, selected_effects, isolate_vocals, preset_name, export_format):
|
|
|
233 |
session_logs = []
|
234 |
|
235 |
for file in files:
|
236 |
+
processed_path, _, _, log = process_audio(file.name, selected_effects, isolate_vocals, preset_name, export_format)
|
237 |
results.append(processed_path)
|
238 |
session_logs.append(log)
|
239 |
|
|
|
246 |
|
247 |
return zip_path
|
248 |
|
249 |
+
# === Gradio Interface Setup ===
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
effect_options = [
|
251 |
"Noise Reduction",
|
252 |
"Compress Dynamic Range",
|
|
|
260 |
]
|
261 |
|
262 |
# === Multi-Tab UI ===
|
263 |
+
with gr.Blocks(title="AI Audio Studio", css="style.css") as demo:
|
264 |
+
gr.Markdown("""
|
265 |
+
# π§ AI Audio Studio β Powered by Hugging Face & Demucs
|
266 |
+
Upload, edit, and export audio with AI-powered tools.
|
267 |
+
""")
|
268 |
|
269 |
# ----- Single File Studio Tab -----
|
270 |
with gr.Tab("π΅ Single File Studio"):
|
|
|
280 |
outputs=[
|
281 |
gr.Audio(label="Processed Audio", type="filepath"),
|
282 |
gr.Image(label="Waveform Preview"),
|
283 |
+
gr.Image(label="Spectrogram View"),
|
284 |
gr.Textbox(label="Session Log (JSON)", lines=5)
|
285 |
],
|
286 |
title="Edit One File at a Time",
|
287 |
+
description="Apply effects, preview waveform and spectrogram, and get full session log.",
|
288 |
+
flagging_mode="never",
|
289 |
+
submit_btn="Process Audio",
|
290 |
+
clear_btn=None
|
291 |
)
|
292 |
|
293 |
# ----- Batch Processing Tab -----
|
|
|
304 |
outputs=gr.File(label="Download ZIP of All Processed Files"),
|
305 |
title="Batch Audio Processor",
|
306 |
description="Upload multiple files, apply effects in bulk, and download all results in a single ZIP.",
|
307 |
+
flagging_mode="never",
|
308 |
submit_btn="Process All Files",
|
309 |
+
clear_btn=None
|
310 |
)
|
311 |
|
312 |
# ----- Remix Mode Tab -----
|
313 |
with gr.Tab("π Remix Mode (Split Stems)"):
|
314 |
def remix_mode(audio_file):
|
315 |
+
stems = stem_split(audio_file.name)
|
316 |
+
return [gr.File(value=stem) for stem in stems]
|
|
|
317 |
|
318 |
gr.Interface(
|
319 |
fn=remix_mode,
|
320 |
inputs=gr.Audio(label="Upload Music Track", type="filepath"),
|
321 |
outputs=[
|
322 |
+
gr.File(label="Vocals"),
|
323 |
+
gr.File(label="Drums"),
|
324 |
+
gr.File(label="Bass"),
|
325 |
+
gr.File(label="Other")
|
326 |
],
|
327 |
+
title="Split Into Drums, Bass, Vocals, and More",
|
328 |
+
description="Use AI to separate musical elements like vocals, drums, and bass.",
|
329 |
+
flagging_mode="never",
|
330 |
+
clear_btn=None
|
331 |
)
|
332 |
|
333 |
+
# ----- Session Info Tab -----
|
334 |
+
with gr.Tab("π Session Info"):
|
335 |
+
def get_session_info(audio_file, selected_effects, isolate_vocals, preset_name, export_format):
|
336 |
+
return generate_session_log(audio_file, selected_effects, isolate_vocals, export_format)
|
337 |
+
|
338 |
gr.Interface(
|
339 |
+
fn=get_session_info,
|
340 |
+
inputs=[
|
341 |
+
gr.Audio(label="Upload Audio", type="filepath"),
|
342 |
+
gr.CheckboxGroup(choices=effect_options, label="Apply Effects in Order"),
|
343 |
+
gr.Checkbox(label="Isolate Vocals After Effects"),
|
344 |
+
gr.Dropdown(choices=preset_names, label="Select Preset", value=preset_names[0] if preset_names else None),
|
345 |
+
gr.Dropdown(choices=["MP3", "WAV"], label="Export Format", value="MP3")
|
346 |
+
],
|
347 |
+
outputs=gr.Textbox(label="Your Session Info (Copy or Save This)", lines=10),
|
348 |
+
title="Save Your Session Settings",
|
349 |
+
description="Get a full log of what was done to your track.",
|
350 |
+
flagging_mode="never",
|
351 |
+
clear_btn=None
|
352 |
)
|
353 |
|
354 |
demo.launch()
|