Spaces:
Sleeping
Sleeping
| # 1. Install necessary libraries | |
| !pip install gradio "demucs>=4.0.0" librosa soundfile matplotlib | |
| # 2. Import libraries | |
| import gradio as gr | |
| import os | |
| import shutil | |
| import asyncio | |
| import librosa | |
| import librosa.display | |
| import soundfile as sf | |
| import numpy as np | |
| import time | |
| import zipfile | |
| import tempfile | |
| import matplotlib.pyplot as plt | |
| import matplotlib | |
| matplotlib.use('Agg') | |
| # --- Helper/Processing Functions --- | |
| def update_output_visibility(choice): | |
| # Now handles 2, 4, and 6 stem visibility | |
| is_6_stem = "6 Stems" in choice | |
| is_4_stem = "4 Stems" in choice | |
| is_2_stem = "2 Stems" in choice | |
| return { | |
| vocals_output: gr.update(visible=True), | |
| drums_output: gr.update(visible=is_4_stem or is_6_stem), | |
| bass_output: gr.update(visible=is_4_stem or is_6_stem), | |
| guitar_output: gr.update(visible=is_6_stem), # Guitar visible only for 6 stems | |
| piano_output: gr.update(visible=is_6_stem), # Piano visible only for 6 stems | |
| other_output: gr.update(visible=True, label="Instrumental (No Vocals)" if is_2_stem else "Other") | |
| } | |
| async def separate_stems(audio_file_path, stem_choice, progress=gr.Progress(track_tqdm=True)): | |
| if audio_file_path is None: raise gr.Error("No audio file uploaded!") | |
| progress(0, desc="Starting...") | |
| try: | |
| progress(0.05, desc="Preparing audio file...") | |
| original_filename_base = os.path.basename(audio_file_path).rsplit('.', 1)[0] | |
| stable_input_path = f"stable_input_{original_filename_base}.wav" | |
| shutil.copy(audio_file_path, stable_input_path) | |
| # Determine Demucs model based on choice | |
| model_name = "htdemucs" # Default to 4-stem model | |
| model_arg = "" | |
| if "2 Stems" in stem_choice: | |
| model_arg = "--two-stems=vocals" | |
| elif "6 Stems" in stem_choice: | |
| model_name = "htdemucs_6s" # Use the 6-stem model | |
| output_dir = "separated" | |
| if os.path.exists(output_dir): shutil.rmtree(output_dir) | |
| # Use -n flag to specify the model name | |
| command = f"python3 -m demucs -n {model_name} {model_arg} -o \"{output_dir}\" \"{stable_input_path}\"" | |
| progress(0.2, desc=f"Running Demucs ({model_name})...") | |
| process = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) | |
| stdout, stderr = await process.communicate() | |
| if process.returncode != 0: | |
| raise gr.Error(f"Demucs failed. Error: {stderr.decode()[:500]}") | |
| progress(0.8, desc="Locating separated stem files...") | |
| stable_filename_base = os.path.basename(stable_input_path).rsplit('.', 1)[0] | |
| # Demucs output folder now matches the model name | |
| stems_path = os.path.join(output_dir, model_name, stable_filename_base) | |
| if not os.path.exists(stems_path): | |
| raise gr.Error(f"Demucs finished, but output directory '{stems_path}' not found!") | |
| # Check for all possible stem files | |
| vocals_path = os.path.join(stems_path, "vocals.wav") if os.path.exists(os.path.join(stems_path, "vocals.wav")) else None | |
| drums_path = os.path.join(stems_path, "drums.wav") if os.path.exists(os.path.join(stems_path, "drums.wav")) else None | |
| bass_path = os.path.join(stems_path, "bass.wav") if os.path.exists(os.path.join(stems_path, "bass.wav")) else None | |
| guitar_path = os.path.join(stems_path, "guitar.wav") if os.path.exists(os.path.join(stems_path, "guitar.wav")) else None | |
| piano_path = os.path.join(stems_path, "piano.wav") if os.path.exists(os.path.join(stems_path, "piano.wav")) else None | |
| # Handle 'other' vs 'no_vocals' based on model | |
| other_filename = "no_vocals.wav" if "2 Stems" in stem_choice else "other.wav" | |
| other_path = os.path.join(stems_path, other_filename) if os.path.exists(os.path.join(stems_path, other_filename)) else None | |
| os.remove(stable_input_path) | |
| return vocals_path, drums_path, bass_path, guitar_path, piano_path, other_path | |
| except Exception as e: | |
| print(f"An error occurred: {e}") | |
| raise gr.Error(str(e)) | |
| # --- Create the full Gradio Interface --- | |
| with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="red")) as demo: | |
| gr.Markdown("# 🎵 Loop Architect") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 1. Separate Stems") | |
| audio_input = gr.Audio(type="filepath", label="Upload a Track") | |
| # Added 6-stem option | |
| stem_options = gr.Radio( | |
| ["6 Stems (Vocals, Drums, Bass, Guitar, Piano, Other)", | |
| "4 Stems (Vocals, Drums, Bass, Other)", | |
| "2 Stems (Vocals + Instrumental)"], | |
| label="Separation Type", | |
| value="4 Stems (Vocals, Drums, Bass, Other)" # Default still 4 stems | |
| ) | |
| submit_button = gr.Button("Separate Stems") | |
| with gr.Column(scale=2): | |
| with gr.Accordion("Separated Stems", open=True): | |
| # Added players for guitar and piano, initially hidden | |
| with gr.Row(): | |
| vocals_output = gr.Audio(label="Vocals", scale=4) | |
| with gr.Row(): | |
| drums_output = gr.Audio(label="Drums", scale=4, visible=True) | |
| with gr.Row(): | |
| bass_output = gr.Audio(label="Bass", scale=4, visible=True) | |
| with gr.Row(): | |
| guitar_output = gr.Audio(label="Guitar", scale=4, visible=False) | |
| with gr.Row(): | |
| piano_output = gr.Audio(label="Piano", scale=4, visible=False) | |
| with gr.Row(): | |
| other_output = gr.Audio(label="Other / Instrumental", scale=4, visible=True) | |
| # --- Define Event Listeners --- | |
| submit_button.click( | |
| fn=separate_stems, | |
| inputs=[audio_input, stem_options], | |
| # Update outputs to include new players | |
| outputs=[vocals_output, drums_output, bass_output, guitar_output, piano_output, other_output] | |
| ) | |
| stem_options.change( | |
| fn=update_output_visibility, | |
| inputs=stem_options, | |
| # Update outputs to include new players | |
| outputs=[vocals_output, drums_output, bass_output, guitar_output, piano_output, other_output] | |
| ) | |
| # --- Launch the UI --- | |
| demo.launch() |