Spaces:
Running
Running
# 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}") | |