# Standard library imports import os import warnings from typing import Annotated, Optional # Related third-party imports import demucs.separate class DemucsVocalSeparator: """ A class for separating vocals from an audio file using the Demucs model. This class utilizes the Demucs model to separate specified audio stems (e.g., vocals) from an input audio file. It supports saving the separated outputs to a specified directory. Attributes ---------- model_name : str Name of the Demucs model to use for separation. two_stems : str The stem to isolate (e.g., "vocals"). Methods ------- separate_vocals(audio_file: str, output_dir: str) -> Optional[str] Separates vocals (or other specified stem) from the audio file and returns the path to the separated file. """ def __init__( self, model_name: Annotated[str, "Demucs model name to use for separation"] = "htdemucs", two_stems: Annotated[str, "Stem to isolate (e.g., vocals, drums)"] = "vocals" ): """ Initializes the DemucsVocalSeparator with the given parameters. Parameters ---------- model_name : str, optional Name of the Demucs model to use for separation (default is "htdemucs"). two_stems : str, optional The stem to isolate (default is "vocals"). """ self.model_name = model_name self.two_stems = two_stems def separate_vocals(self, audio_file: str, output_dir: str) -> Optional[str]: """ Separates vocals (or other specified stem) from the audio file. This method invokes the Demucs model to isolate a specified audio stem (e.g., vocals). The output is saved in WAV format in the specified output directory. Parameters ---------- audio_file : str Path to the input audio file. output_dir : str Directory where the separated files will be saved. Returns ------- Optional[str] Path to the separated vocal file if successful, or the original audio file path if not. Raises ------ Warning If vocal separation fails or the separated file is not found. Examples -------- >>> separator = DemucsVocalSeparator() >>> vocal_path = separator.separate_vocals("path/to/audio/file.mp3", "output_dir") Vocal separation successful! Outputs saved in WAV format at 'output_dir' directory. """ demucs_args = [ "--two-stems", self.two_stems, "-n", self.model_name, "-o", output_dir, audio_file ] try: demucs.separate.main(demucs_args) print(f"Vocal separation successful! Outputs saved in WAV format at '{output_dir}' directory.") output_path = os.path.join( output_dir, self.model_name, os.path.splitext(os.path.basename(audio_file))[0] ) vocal_file = os.path.join(output_path, f"{self.two_stems}.wav") if os.path.exists(vocal_file): return vocal_file else: print("Separated vocal file not found. Returning original audio file path.") warnings.warn("Vocal separation was unsuccessful; using the original audio file.", stacklevel=2) return audio_file except Exception as e: print(f"An error occurred during vocal separation: {e}") warnings.warn("Vocal separation failed; proceeding with the original audio file.", stacklevel=2) return audio_file if __name__ == "__main__": file = "example_audio.mp3" output_directory = "separated_outputs" vocal_separator = DemucsVocalSeparator() separated_file_path = vocal_separator.separate_vocals(file, output_directory) print(f"Separated file path: {separated_file_path}")