Spaces:
Running
Running
Commit
·
c9c6048
1
Parent(s):
7f4210b
Moved Music_Splitter contents into the main repository
Browse files- .gitattributes +0 -35
- .gitignore +3 -0
- .gitmodules +3 -0
- .idea/.gitignore +8 -0
- .idea/.name +1 -0
- .idea/audio_splitter.iml +10 -0
- .idea/inspectionProfiles/profiles_settings.xml +6 -0
- .idea/misc.xml +7 -0
- .idea/modules.xml +8 -0
- .idea/vcs.xml +7 -0
- Dockerfile +25 -0
- README.md +121 -13
- app.py +135 -0
- audio_processor.py +50 -0
- requirements.txt +4 -0
- video_processor.py +42 -0
.gitattributes
DELETED
@@ -1,35 +0,0 @@
|
|
1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
__pycache__/
|
2 |
+
*.pyc
|
3 |
+
.env
|
.gitmodules
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
[submodule "Music_Splitter"]
|
2 |
+
path = Music_Splitter
|
3 |
+
url = https://huggingface.co/spaces/Omar-youssef/Music_Splitter
|
.idea/.gitignore
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Default ignored files
|
2 |
+
/shelf/
|
3 |
+
/workspace.xml
|
4 |
+
# Editor-based HTTP Client requests
|
5 |
+
/httpRequests/
|
6 |
+
# Datasource local storage ignored files
|
7 |
+
/dataSources/
|
8 |
+
/dataSources.local.xml
|
.idea/.name
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
app.py
|
.idea/audio_splitter.iml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<module type="PYTHON_MODULE" version="4">
|
3 |
+
<component name="NewModuleRootManager">
|
4 |
+
<content url="file://$MODULE_DIR$">
|
5 |
+
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
6 |
+
</content>
|
7 |
+
<orderEntry type="jdk" jdkName="Python 3.9 virtualenv at C:\Users\abdom\PycharmProjects\pushToHuggingface\.venv" jdkType="Python SDK" />
|
8 |
+
<orderEntry type="sourceFolder" forTests="false" />
|
9 |
+
</component>
|
10 |
+
</module>
|
.idea/inspectionProfiles/profiles_settings.xml
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<component name="InspectionProjectProfileManager">
|
2 |
+
<settings>
|
3 |
+
<option name="USE_PROJECT_PROFILE" value="false" />
|
4 |
+
<version value="1.0" />
|
5 |
+
</settings>
|
6 |
+
</component>
|
.idea/misc.xml
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="Black">
|
4 |
+
<option name="sdkName" value="Python 3.9 (audio_splitter)" />
|
5 |
+
</component>
|
6 |
+
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 virtualenv at C:\Users\abdom\PycharmProjects\pushToHuggingface\.venv" project-jdk-type="Python SDK" />
|
7 |
+
</project>
|
.idea/modules.xml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="ProjectModuleManager">
|
4 |
+
<modules>
|
5 |
+
<module fileurl="file://$PROJECT_DIR$/.idea/audio_splitter.iml" filepath="$PROJECT_DIR$/.idea/audio_splitter.iml" />
|
6 |
+
</modules>
|
7 |
+
</component>
|
8 |
+
</project>
|
.idea/vcs.xml
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="VcsDirectoryMappings">
|
4 |
+
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
5 |
+
<mapping directory="$PROJECT_DIR$/Music_Splitter" vcs="Git" />
|
6 |
+
</component>
|
7 |
+
</project>
|
Dockerfile
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use Python 3.9 as base image
|
2 |
+
FROM python:3.9-slim
|
3 |
+
|
4 |
+
# Install system dependencies
|
5 |
+
RUN apt-get update && apt-get install -y \
|
6 |
+
ffmpeg \
|
7 |
+
&& rm -rf /var/lib/apt/lists/*
|
8 |
+
|
9 |
+
# Set working directory
|
10 |
+
WORKDIR /app
|
11 |
+
|
12 |
+
# Copy requirements first to leverage Docker cache
|
13 |
+
COPY requirements.txt .
|
14 |
+
|
15 |
+
# Install Python dependencies
|
16 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
17 |
+
|
18 |
+
# Copy the application code
|
19 |
+
COPY . .
|
20 |
+
|
21 |
+
# Expose the port Streamlit runs on
|
22 |
+
EXPOSE 8501
|
23 |
+
|
24 |
+
# Command to run the application
|
25 |
+
CMD ["streamlit", "run", "main.py", "--server.address", "0.0.0.0"]
|
README.md
CHANGED
@@ -1,13 +1,121 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 🎵 Audio/Video Music Splitter
|
2 |
+
|
3 |
+
A Streamlit-based web application that allows users to separate vocals from audio files and videos. This tool uses the Demucs model for high-quality audio source separation.
|
4 |
+
|
5 |
+

|
6 |
+
|
7 |
+
|
8 |
+
## 🌟 Features
|
9 |
+
|
10 |
+
- **Audio Processing**: Extract vocals from audio files (MP3, WAV, OGG)
|
11 |
+
- **Video Processing**: Separate vocals from video files (MP4, MKV, AVI)
|
12 |
+
- **Download Options**:
|
13 |
+
- Download isolated vocals
|
14 |
+
- Download processed video with isolated vocals
|
15 |
+
- **User-Friendly Interface**: Simple drag-and-drop file upload
|
16 |
+
- **Multiple Format Support**: Works with various audio and video formats
|
17 |
+
|
18 |
+
## 🚀 Getting Started
|
19 |
+
|
20 |
+
### Prerequisites
|
21 |
+
|
22 |
+
- Docker installed on your system
|
23 |
+
- At least 4GB of available RAM
|
24 |
+
- 2GB of free disk space
|
25 |
+
|
26 |
+
### Quick Start with Docker
|
27 |
+
|
28 |
+
1. Clone the repository:
|
29 |
+
```bash
|
30 |
+
git clone https://github.com/yourusername/Omar-YYoussef-Audio_Video_Music_Splitter.git
|
31 |
+
cd Omar-YYoussef-Audio_Video_Music_Splitter
|
32 |
+
```
|
33 |
+
|
34 |
+
2. Build the Docker image:
|
35 |
+
```bash
|
36 |
+
docker build -t audio-video-splitter .
|
37 |
+
```
|
38 |
+
|
39 |
+
3. Run the container:
|
40 |
+
```bash
|
41 |
+
docker run -p 8501:8501 audio-video-splitter
|
42 |
+
```
|
43 |
+
|
44 |
+
4. Open your browser and navigate to:
|
45 |
+
```
|
46 |
+
http://localhost:8501
|
47 |
+
```
|
48 |
+
|
49 |
+
### Manual Installation
|
50 |
+
|
51 |
+
1. Install system dependencies:
|
52 |
+
```bash
|
53 |
+
# Ubuntu/Debian
|
54 |
+
sudo apt-get update && sudo apt-get install -y ffmpeg
|
55 |
+
|
56 |
+
# MacOS
|
57 |
+
brew install ffmpeg
|
58 |
+
|
59 |
+
# Windows
|
60 |
+
# Download and install ffmpeg from https://ffmpeg.org/download.html
|
61 |
+
```
|
62 |
+
|
63 |
+
2. Install Python dependencies:
|
64 |
+
```bash
|
65 |
+
pip install -r requirements.txt
|
66 |
+
```
|
67 |
+
|
68 |
+
3. Run the application:
|
69 |
+
```bash
|
70 |
+
streamlit run main.py
|
71 |
+
```
|
72 |
+
|
73 |
+
## 💡 Usage
|
74 |
+
|
75 |
+
### Processing Audio Files
|
76 |
+
|
77 |
+
1. Select the "Audio Processing 🎧" tab
|
78 |
+
2. Upload your audio file (MP3, WAV, or OGG format)
|
79 |
+
3. Click "Process Audio"
|
80 |
+
4. Download the separated vocals
|
81 |
+
|
82 |
+
### Processing Video Files
|
83 |
+
|
84 |
+
1. Select the "Video Processing 🎥" tab
|
85 |
+
2. Upload your video file (MP4, MKV, or AVI format)
|
86 |
+
3. Click "Process Video"
|
87 |
+
4. Download either:
|
88 |
+
- The processed video with isolated vocals
|
89 |
+
- The separated vocals as an audio file
|
90 |
+
|
91 |
+

|
92 |
+
|
93 |
+
|
94 |
+
## 🔧 Technical Details
|
95 |
+
|
96 |
+
The application uses several key technologies:
|
97 |
+
|
98 |
+
- **Streamlit**: For the web interface
|
99 |
+
- **Demucs**: For audio source separation
|
100 |
+
- **FFmpeg**: For audio/video processing
|
101 |
+
- **Python 3.9**: As the base programming language
|
102 |
+
|
103 |
+
|
104 |
+
## 🤝 Contributing
|
105 |
+
|
106 |
+
1. Fork the repository
|
107 |
+
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
108 |
+
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
109 |
+
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
110 |
+
5. Open a Pull Request
|
111 |
+
|
112 |
+
## 📝 License
|
113 |
+
|
114 |
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
115 |
+
|
116 |
+
## 👏 Acknowledgments
|
117 |
+
|
118 |
+
- [Demucs](https://github.com/facebookresearch/demucs) for the audio separation model
|
119 |
+
- [Streamlit](https://streamlit.io/) for the web app framework
|
120 |
+
- [FFmpeg](https://ffmpeg.org/) for media processing capabilities
|
121 |
+
|
app.py
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import tempfile
|
3 |
+
import os
|
4 |
+
from pathlib import Path
|
5 |
+
from video_processor import VideoProcessor
|
6 |
+
from audio_processor import AudioProcessor
|
7 |
+
|
8 |
+
# Utility functions
|
9 |
+
def save_uploaded_file(uploaded_file, temp_dir):
|
10 |
+
file_path = Path(temp_dir) / uploaded_file.name
|
11 |
+
with open(file_path, 'wb') as f:
|
12 |
+
f.write(uploaded_file.read())
|
13 |
+
return file_path
|
14 |
+
|
15 |
+
def download_file_button(file_path, label, file_name, mime_type):
|
16 |
+
with open(file_path, 'rb') as f:
|
17 |
+
st.download_button(
|
18 |
+
label=label,
|
19 |
+
data=f.read(),
|
20 |
+
file_name=file_name,
|
21 |
+
mime=mime_type
|
22 |
+
)
|
23 |
+
|
24 |
+
def process_audio(audio_file):
|
25 |
+
with tempfile.TemporaryDirectory() as temp_dir:
|
26 |
+
# Save uploaded file
|
27 |
+
input_path = save_uploaded_file(audio_file, temp_dir)
|
28 |
+
|
29 |
+
# Create output directory
|
30 |
+
output_dir = Path(temp_dir) / "output"
|
31 |
+
output_dir.mkdir(exist_ok=True)
|
32 |
+
|
33 |
+
with st.spinner("Processing audio..."):
|
34 |
+
try:
|
35 |
+
audio_proc = AudioProcessor(input_path, output_dir)
|
36 |
+
|
37 |
+
# Run Demucs
|
38 |
+
if not audio_proc.run_demucs():
|
39 |
+
raise RuntimeError("Demucs processing failed.")
|
40 |
+
|
41 |
+
# Retrieve processed files
|
42 |
+
vocals_path = audio_proc.get_vocals_path()
|
43 |
+
no_vocals_path = audio_proc.get_no_vocals_path()
|
44 |
+
|
45 |
+
if not vocals_path or not no_vocals_path:
|
46 |
+
raise FileNotFoundError("Processed files not found.")
|
47 |
+
|
48 |
+
# Download buttons
|
49 |
+
col1, col2 = st.columns(2)
|
50 |
+
download_file_button(vocals_path, "Download Vocals", f"vocals_{audio_file.name.rsplit('.', 1)[0]}.wav", "audio/wav")
|
51 |
+
# download_file_button(no_vocals_path, "Download Instrumental", f"instrumental_{audio_file.name.rsplit('.', 1)[0]}.wav", "audio/wav")
|
52 |
+
|
53 |
+
st.success("Audio processing completed!")
|
54 |
+
|
55 |
+
except Exception as e:
|
56 |
+
st.error(f"An error occurred: {str(e)}")
|
57 |
+
|
58 |
+
def process_video(video_file):
|
59 |
+
with tempfile.TemporaryDirectory() as temp_dir:
|
60 |
+
# Save uploaded file
|
61 |
+
input_path = save_uploaded_file(video_file, temp_dir)
|
62 |
+
|
63 |
+
# Create output directory
|
64 |
+
output_dir = Path(temp_dir) / "output"
|
65 |
+
output_dir.mkdir(exist_ok=True)
|
66 |
+
|
67 |
+
with st.spinner("Processing video..."):
|
68 |
+
try:
|
69 |
+
# Extract audio from video
|
70 |
+
video_proc = VideoProcessor(input_path, output_dir)
|
71 |
+
audio_path = video_proc.extract_audio()
|
72 |
+
if not audio_path:
|
73 |
+
raise RuntimeError("Audio extraction from video failed.")
|
74 |
+
|
75 |
+
# Process extracted audio
|
76 |
+
audio_proc = AudioProcessor(audio_path, output_dir)
|
77 |
+
if not audio_proc.run_demucs():
|
78 |
+
raise RuntimeError("Demucs processing failed.")
|
79 |
+
|
80 |
+
# Retrieve processed audio files
|
81 |
+
vocals_path = audio_proc.get_vocals_path()
|
82 |
+
no_vocals_path = audio_proc.get_no_vocals_path()
|
83 |
+
if not vocals_path or not no_vocals_path:
|
84 |
+
raise FileNotFoundError("Processed audio files not found.")
|
85 |
+
|
86 |
+
# Combine video with vocals
|
87 |
+
final_video_path = video_proc.combine_video_audio(vocals_path)
|
88 |
+
|
89 |
+
# Download buttons
|
90 |
+
col1, col2, col3 = st.columns(3)
|
91 |
+
if final_video_path:
|
92 |
+
download_file_button(final_video_path, "Download Processed Video", f"processed_{video_file.name}", "video/mp4")
|
93 |
+
download_file_button(vocals_path, "Download Vocals", f"vocals_{video_file.name.rsplit('.', 1)[0]}.wav", "audio/wav")
|
94 |
+
#download_file_button(no_vocals_path, "Download Instrumental", f"instrumental_{video_file.name.rsplit('.', 1)[0]}.wav", "audio/wav")
|
95 |
+
|
96 |
+
st.success("Video processing completed!")
|
97 |
+
|
98 |
+
except Exception as e:
|
99 |
+
st.error(f"An error occurred: {str(e)}")
|
100 |
+
|
101 |
+
# Streamlit App Layout
|
102 |
+
st.title("🎵 Audio/Video Vocal Separator")
|
103 |
+
|
104 |
+
# Tabs for different processing types
|
105 |
+
tab1, tab2 = st.tabs(["Audio Processing 🎧", "Video Processing 🎥"])
|
106 |
+
|
107 |
+
with tab1:
|
108 |
+
st.header("Process Your Audio File")
|
109 |
+
with st.expander("Instructions", expanded=True):
|
110 |
+
st.markdown("""
|
111 |
+
1. Upload an audio file in MP3, WAV, or OGG format.
|
112 |
+
2. Click the **Process Audio** button.
|
113 |
+
3. Download the separated vocals.
|
114 |
+
""")
|
115 |
+
audio_file = st.file_uploader("Upload your audio file", type=['mp3', 'wav', 'ogg'])
|
116 |
+
if audio_file and st.button("Process Audio"):
|
117 |
+
process_audio(audio_file)
|
118 |
+
|
119 |
+
with tab2:
|
120 |
+
st.header("Process Your Video File")
|
121 |
+
with st.expander("Instructions", expanded=True):
|
122 |
+
st.markdown("""
|
123 |
+
1. Upload a video file in MP4, MKV, or AVI format.
|
124 |
+
2. Click the **Process Video** button.
|
125 |
+
3. Download the processed video or vocals.
|
126 |
+
""")
|
127 |
+
video_file = st.file_uploader("Upload your video file", type=['mp4', 'mkv', 'avi'])
|
128 |
+
if video_file and st.button("Process Video"):
|
129 |
+
process_video(video_file)
|
130 |
+
|
131 |
+
# Footer
|
132 |
+
st.markdown("""
|
133 |
+
---
|
134 |
+
Made with ❤️ using [Streamlit](https://streamlit.io)
|
135 |
+
""")
|
audio_processor.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
import subprocess
|
3 |
+
|
4 |
+
class AudioProcessor:
|
5 |
+
def __init__(self, input_audio, output_dir):
|
6 |
+
self.input_audio = Path(input_audio)
|
7 |
+
self.output_dir = Path(output_dir)
|
8 |
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
9 |
+
|
10 |
+
def run_demucs(self):
|
11 |
+
"""Process audio using Demucs to separate vocals"""
|
12 |
+
try:
|
13 |
+
# Use default model (htdemucs) without MP3 output to avoid diffq dependency
|
14 |
+
subprocess.run([
|
15 |
+
"demucs",
|
16 |
+
"--two-stems=vocals",
|
17 |
+
"-o", str(self.output_dir),
|
18 |
+
str(self.input_audio)
|
19 |
+
], check=True)
|
20 |
+
print("Demucs processing completed successfully")
|
21 |
+
return True
|
22 |
+
except subprocess.CalledProcessError as e:
|
23 |
+
print(f"Error during Demucs execution: {e}")
|
24 |
+
return False
|
25 |
+
|
26 |
+
def get_vocals_path(self):
|
27 |
+
"""Get path to the separated vocals file"""
|
28 |
+
# Path for htdemucs model output
|
29 |
+
vocals_path = self.output_dir / "htdemucs" / Path(self.input_audio.stem) / "vocals.wav"
|
30 |
+
if vocals_path.exists():
|
31 |
+
print(f"Vocals found at: {vocals_path}")
|
32 |
+
return str(vocals_path)
|
33 |
+
print("Vocals file not found")
|
34 |
+
return None
|
35 |
+
|
36 |
+
def get_no_vocals_path(self):
|
37 |
+
"""Get path to the no-vocals (instrumental) file"""
|
38 |
+
# Path for htdemucs model output
|
39 |
+
no_vocals_path = self.output_dir / "htdemucs" / Path(self.input_audio.stem) / "no_vocals.wav"
|
40 |
+
if no_vocals_path.exists():
|
41 |
+
print(f"No-vocals track found at: {no_vocals_path}")
|
42 |
+
return str(no_vocals_path)
|
43 |
+
print("No-vocals file not found")
|
44 |
+
return None
|
45 |
+
|
46 |
+
def cleanup(self):
|
47 |
+
"""Remove temporary audio files"""
|
48 |
+
if self.input_audio.exists():
|
49 |
+
self.input_audio.unlink()
|
50 |
+
print("Temporary audio files cleaned up")
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit>=1.24.0
|
2 |
+
demucs
|
3 |
+
ffmpeg-python
|
4 |
+
pathlib
|
video_processor.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
import subprocess
|
3 |
+
|
4 |
+
class VideoProcessor:
|
5 |
+
def __init__(self, input_video, output_dir):
|
6 |
+
self.input_video = Path(input_video)
|
7 |
+
self.output_dir = Path(output_dir)
|
8 |
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
9 |
+
self.temp_audio = self.output_dir / "extracted_audio.wav"
|
10 |
+
self.final_video = self.output_dir / "final_video.mp4"
|
11 |
+
|
12 |
+
def extract_audio(self):
|
13 |
+
"""Extract audio from video file"""
|
14 |
+
try:
|
15 |
+
subprocess.run([
|
16 |
+
"ffmpeg", "-i", str(self.input_video),
|
17 |
+
"-vn", "-acodec", "pcm_s16le", "-ar", "44100",
|
18 |
+
str(self.temp_audio)
|
19 |
+
], check=True)
|
20 |
+
print(f"Audio extracted successfully to {self.temp_audio}")
|
21 |
+
return str(self.temp_audio)
|
22 |
+
except subprocess.CalledProcessError as e:
|
23 |
+
print(f"Error extracting audio: {e}")
|
24 |
+
return None
|
25 |
+
|
26 |
+
def combine_video_audio(self, vocals_path):
|
27 |
+
"""Combine original video with vocals only"""
|
28 |
+
try:
|
29 |
+
subprocess.run([
|
30 |
+
"ffmpeg",
|
31 |
+
"-i", str(self.input_video),
|
32 |
+
"-i", vocals_path,
|
33 |
+
"-c:v", "copy",
|
34 |
+
"-c:a", "aac",
|
35 |
+
"-map", "0:v:0",
|
36 |
+
"-map", "1:a:0",
|
37 |
+
str(self.final_video)
|
38 |
+
], check=True)
|
39 |
+
return str(self.final_video)
|
40 |
+
except subprocess.CalledProcessError as e:
|
41 |
+
print(f"Error combining video and audio: {e}")
|
42 |
+
return None
|