ahkd commited on
Commit
f18255f
Β·
1 Parent(s): bb4c67f

test spleeter

Browse files
Files changed (2) hide show
  1. app.py +106 -176
  2. requirements.txt +2 -4
app.py CHANGED
@@ -8,13 +8,11 @@ from demucs.apply import apply_model
8
  import os
9
  import tempfile
10
  import numpy as np
11
- from spleeter.separator import Separator
12
- from spleeter.audio.adapter import AudioAdapter
13
  import warnings
14
  import soundfile as sf
15
  import librosa
16
- import requests
17
- import tarfile
18
  import shutil
19
  warnings.filterwarnings("ignore")
20
 
@@ -30,73 +28,29 @@ htdemucs_model = htdemucs_model.to(device)
30
  htdemucs_model.eval()
31
  print("HT-Demucs model loaded successfully.")
32
 
33
- # Load Spleeter model with better error handling
34
- print("Loading Spleeter model...")
35
- spleeter_separator = None
36
- spleeter_audio_adapter = None
37
 
38
- try:
39
- # Set up environment variables for better model handling
40
- os.environ['SPLEETER_MODEL_PATH'] = '/tmp/spleeter_models'
41
- os.makedirs('/tmp/spleeter_models', exist_ok=True)
42
-
43
- # Try different approaches to handle the redirect issue
44
- import ssl
45
- import urllib.request
46
- import urllib3
47
- urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
48
-
49
- # Create unverified SSL context to handle redirects
50
- ssl._create_default_https_context = ssl._create_unverified_context
51
-
52
  try:
53
- print("Attempting to load 5stems model...")
54
- # Try with specific configuration to handle redirects
55
- spleeter_separator = Separator(
56
- 'spleeter:5stems',
57
- multiprocess=False,
58
- stft_backend='tensorflow'
59
- )
60
- spleeter_model_type = "5stems"
61
- print("Spleeter: Using 5stems model (vocals, drums, bass, other, piano)")
62
- except Exception as e5:
63
- print(f"5stems model failed: {e5}")
64
- try:
65
- print("Attempting to load 2stems model...")
66
- spleeter_separator = Separator(
67
- 'spleeter:2stems',
68
- multiprocess=False,
69
- stft_backend='tensorflow'
70
- )
71
- spleeter_model_type = "2stems"
72
- print("Spleeter: Using 2stems model (vocals, accompaniment)")
73
- except Exception as e2:
74
- print(f"2stems model also failed: {e2}")
75
- try:
76
- print("Attempting to load 2stems-16kHz model...")
77
- spleeter_separator = Separator(
78
- 'spleeter:2stems-16kHz',
79
- multiprocess=False,
80
- stft_backend='tensorflow'
81
- )
82
- spleeter_model_type = "2stems-16kHz"
83
- print("Spleeter: Using 2stems-16kHz model")
84
- except Exception as e3:
85
- print(f"All Spleeter models failed: {e3}")
86
- spleeter_separator = None
87
- spleeter_model_type = None
88
-
89
- if spleeter_separator is not None:
90
- spleeter_audio_adapter = AudioAdapter.default()
91
- print("Spleeter model loaded successfully.")
92
- else:
93
- print("Spleeter will be disabled for this session.")
94
-
95
- except Exception as e:
96
- print(f"Spleeter initialization failed: {e}")
97
- spleeter_separator = None
98
- spleeter_audio_adapter = None
99
- spleeter_model_type = None
100
 
101
  # --- HT-Demucs separation function ---
102
  def separate_with_htdemucs(audio_path):
@@ -124,14 +78,16 @@ def separate_with_htdemucs(audio_path):
124
  sources = apply_model(htdemucs_model, wav[None], device=device, progress=True)[0]
125
  print("HT-Demucs: Separation complete.")
126
 
127
- # Save stems temporarily
128
- stem_names = ["drums", "bass", "other", "vocals"]
129
- output_dir = "htdemucs_stems"
130
  os.makedirs(output_dir, exist_ok=True)
 
 
131
 
132
  output_paths = []
133
  for i, name in enumerate(stem_names):
134
- out_path = os.path.join(output_dir, f"{name}.wav")
135
  torchaudio.save(out_path, sources[i].cpu(), sr)
136
  output_paths.append(out_path)
137
  print(f"βœ… HT-Demucs saved {name} to {out_path}")
@@ -146,103 +102,79 @@ def separate_with_htdemucs(audio_path):
146
  def separate_with_spleeter(audio_path):
147
  """
148
  Separates an audio file using Spleeter into vocals, drums, bass, other, and piano.
 
149
  Returns FILE PATHS.
150
  """
151
  if audio_path is None:
152
  return None, None, None, None, None, "Please upload an audio file."
153
 
154
- if spleeter_separator is None or spleeter_audio_adapter is None:
155
- return None, None, None, None, None, "❌ Spleeter model not loaded properly."
156
 
157
  try:
158
- print(f"Spleeter: Loading audio from: {audio_path}")
159
 
160
- # Use librosa for more robust audio loading
161
- try:
162
- # Load audio with librosa (handles more formats reliably)
163
- waveform, sample_rate = librosa.load(audio_path, sr=44100, mono=False)
164
- print(f"Spleeter (librosa): Loaded audio - shape: {waveform.shape}, sr: {sample_rate}")
165
-
166
- # Handle different audio shapes
167
- if waveform.ndim == 1:
168
- # Mono audio - convert to stereo for Spleeter
169
- print("Spleeter: Converting mono to stereo")
170
- waveform = np.stack([waveform, waveform], axis=0)
171
- elif waveform.ndim == 2 and waveform.shape[0] == 2:
172
- # Stereo audio - already correct format
173
- print("Spleeter: Stereo audio detected")
174
- else:
175
- print(f"Spleeter: Unexpected shape {waveform.shape}, converting...")
176
- if waveform.shape[0] > waveform.shape[1]:
177
- # Transpose if needed (samples, channels) -> (channels, samples)
178
- waveform = waveform.T
179
- if waveform.shape[0] == 1:
180
- waveform = np.vstack([waveform, waveform])
181
- elif waveform.shape[0] > 2:
182
- # Take first two channels if more than stereo
183
- waveform = waveform[:2, :]
184
-
185
- print(f"Spleeter: Final waveform shape: {waveform.shape}")
186
-
187
- # Transpose to (samples, channels) format for Spleeter
188
- waveform_for_spleeter = waveform.T
189
- print(f"Spleeter: Transposed for separation - shape: {waveform_for_spleeter.shape}")
190
-
191
- except Exception as load_error:
192
- print(f"Librosa loading failed: {load_error}")
193
- # Fallback to spleeter's audio adapter
194
- waveform_for_spleeter, sample_rate = spleeter_audio_adapter.load(audio_path)
195
- print(f"Spleeter (adapter): Loaded audio - shape: {waveform_for_spleeter.shape}, sr: {sample_rate}")
196
 
197
- print("Spleeter: Applying the separation model...")
198
- # Use the waveform directly with Spleeter
199
- prediction = spleeter_separator.separate(waveform_for_spleeter)
200
  print("Spleeter: Separation complete.")
201
- print(f"Spleeter: Prediction keys: {list(prediction.keys())}")
202
-
203
- # Save stems temporarily
204
- output_dir = "spleeter_stems"
205
- os.makedirs(output_dir, exist_ok=True)
206
-
207
- output_paths = []
208
 
209
- # Handle different model types
210
- if spleeter_model_type == "5stems":
211
- # 5stems model
212
- stem_names = ["vocals", "drums", "bass", "other", "piano"]
213
- else:
214
- # 2stems model
215
- stem_names = ["vocals", "accompaniment", None, None, None]
216
 
217
- for i, name in enumerate(stem_names):
218
- if name is not None and name in prediction:
219
- out_path = os.path.join(output_dir, f"{name}.wav")
220
- stem_audio = prediction[name]
221
-
222
- print(f"Spleeter: {name} audio shape: {stem_audio.shape}, dtype: {stem_audio.dtype}")
223
-
224
- # Ensure correct format for saving
225
- if stem_audio.ndim == 1:
226
- # Mono - reshape to (samples, 1)
227
- stem_audio = stem_audio.reshape(-1, 1)
228
- elif stem_audio.ndim == 2:
229
- # Check if it's (channels, samples) and transpose if needed
230
- if stem_audio.shape[0] < stem_audio.shape[1] and stem_audio.shape[0] <= 2:
231
- stem_audio = stem_audio.T
232
-
233
- # Save using soundfile for better compatibility
234
- sf.write(out_path, stem_audio, sample_rate)
235
- output_paths.append(out_path)
236
- print(f"βœ… Spleeter saved {name} to {out_path}")
 
 
237
  else:
 
238
  output_paths.append(None)
239
 
240
- # Ensure we have 5 outputs
241
- while len(output_paths) < 5:
242
- output_paths.append(None)
243
-
244
  return output_paths[0], output_paths[1], output_paths[2], output_paths[3], output_paths[4], "βœ… Spleeter separation successful!"
245
 
 
 
246
  except Exception as e:
247
  print(f"Spleeter Error: {e}")
248
  import traceback
@@ -302,12 +234,12 @@ def separate_selected_models(audio_path, run_htdemucs, run_spleeter):
302
  print("Creating Gradio interface...")
303
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
304
  gr.Markdown("""
305
- # 🎡 Music Stem Separator - HT-Demucs & Spleeter Comparison
306
 
307
  Upload your music and get stems from both **HT-Demucs** and **Spleeter** models!
308
 
309
  **HT-Demucs** provides: Drums, Bass, Other, Vocals
310
- **Spleeter** provides: Vocals, Drums, Bass, Other, **Piano** 🎹 (5stems model)
311
 
312
  Compare the quality and choose the best stems for your needs!
313
  """)
@@ -320,12 +252,11 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
320
  gr.Markdown("### πŸŽ›οΈ Select Models to Run")
321
  with gr.Row():
322
  htdemucs_toggle = gr.Checkbox(label="🎯 HT-Demucs", value=True, info="Drums, Bass, Other, Vocals")
323
- spleeter_enabled = spleeter_separator is not None
324
  spleeter_toggle = gr.Checkbox(
325
- label="🎡 Spleeter",
326
- value=spleeter_enabled,
327
- info=f"Available: {spleeter_model_type}" if spleeter_enabled else "Not available",
328
- interactive=spleeter_enabled
329
  )
330
 
331
  separate_button = gr.Button("πŸš€ Separate Music", variant="primary", size="lg")
@@ -346,7 +277,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
346
 
347
  # Spleeter Results
348
  with gr.Column():
349
- gr.Markdown("### 🎡 Spleeter Results")
350
  with gr.Row():
351
  spleeter_vocals = gr.Audio(label="🎀 Vocals", type="filepath")
352
  spleeter_drums = gr.Audio(label="πŸ₯ Drums", type="filepath")
@@ -356,10 +287,10 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
356
  with gr.Row():
357
  spleeter_piano = gr.Audio(label="🎹 Piano", type="filepath")
358
 
359
- if spleeter_model_type == "2stems":
360
- gr.Markdown("*Note: Only Vocals and Accompaniment available with 2stems model*")
361
- elif not spleeter_enabled:
362
- gr.Markdown("*Note: Spleeter model not available*")
363
 
364
  gr.Markdown("---")
365
 
@@ -367,18 +298,17 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
367
  comparison_text = f"""
368
  ### πŸ“‹ Model Comparison
369
 
370
- | Feature | HT-Demucs | Spleeter ({spleeter_model_type if spleeter_model_type else 'N/A'}) |
371
  |---------|-----------|----------|
372
- | **Vocals** | βœ… High Quality | {'βœ… Available' if spleeter_enabled else '❌ N/A'} |
373
- | **Drums** | βœ… High Quality | {'βœ… Available' if spleeter_model_type == '5stems' else '❌ N/A'} |
374
- | **Bass** | βœ… High Quality | {'βœ… Available' if spleeter_model_type == '5stems' else '❌ N/A'} |
375
- | **Other** | βœ… High Quality | {'βœ… Available' if spleeter_model_type == '5stems' else '❌ N/A'} |
376
- | **Piano** | ❌ Not Available | {'βœ… Available' if spleeter_model_type == '5stems' else '❌ N/A'} |
377
- | **Accompaniment** | ❌ Not Available | {'βœ… Available' if spleeter_model_type == '2stems' else '❌ N/A'} |
378
- | **Speed** | ⚑ Fast | {'⚑ Fast' if spleeter_enabled else '❌ N/A'} |
379
- | **Quality** | πŸ† Excellent | {'πŸ† Good' if spleeter_enabled else '❌ N/A'} |
380
 
381
- **πŸ’‘ Tip:** Use Spleeter when you need piano separation, HT-Demucs for other instruments!
382
  """
383
  gr.Markdown(comparison_text)
384
 
@@ -396,7 +326,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
396
  gr.Markdown("""
397
  ---
398
  <p style='text-align: center; font-size: small;'>
399
- πŸš€ Powered by <strong>HT-Demucs</strong> & <strong>Spleeter</strong> |
400
  🎡 Compare and choose your best stems!
401
  </p>
402
  """)
 
8
  import os
9
  import tempfile
10
  import numpy as np
 
 
11
  import warnings
12
  import soundfile as sf
13
  import librosa
14
+ import time
15
+ import subprocess
16
  import shutil
17
  warnings.filterwarnings("ignore")
18
 
 
28
  htdemucs_model.eval()
29
  print("HT-Demucs model loaded successfully.")
30
 
31
+ # Setup Spleeter with command-line approach
32
+ print("Setting up Spleeter...")
33
+ spleeter_available = False
 
34
 
35
+ def check_spleeter_installation():
36
+ """Check if Spleeter is installed and available via command line"""
 
 
 
 
 
 
 
 
 
 
 
 
37
  try:
38
+ result = subprocess.run(['spleeter', '--help'],
39
+ capture_output=True, text=True, timeout=10)
40
+ if result.returncode == 0:
41
+ print("βœ… Spleeter command-line tool is available!")
42
+ return True
43
+ else:
44
+ print(f"❌ Spleeter command failed: {result.stderr}")
45
+ return False
46
+ except FileNotFoundError:
47
+ print("❌ Spleeter command not found. Please install Spleeter.")
48
+ return False
49
+ except Exception as e:
50
+ print(f"❌ Error checking Spleeter: {e}")
51
+ return False
52
+
53
+ spleeter_available = check_spleeter_installation()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
  # --- HT-Demucs separation function ---
56
  def separate_with_htdemucs(audio_path):
 
78
  sources = apply_model(htdemucs_model, wav[None], device=device, progress=True)[0]
79
  print("HT-Demucs: Separation complete.")
80
 
81
+ # Save stems with timestamp to ensure uniqueness
82
+ timestamp = int(time.time() * 1000) # millisecond timestamp
83
+ output_dir = f"htdemucs_stems_{timestamp}"
84
  os.makedirs(output_dir, exist_ok=True)
85
+
86
+ stem_names = ["drums", "bass", "other", "vocals"]
87
 
88
  output_paths = []
89
  for i, name in enumerate(stem_names):
90
+ out_path = os.path.join(output_dir, f"{name}_{timestamp}.wav")
91
  torchaudio.save(out_path, sources[i].cpu(), sr)
92
  output_paths.append(out_path)
93
  print(f"βœ… HT-Demucs saved {name} to {out_path}")
 
102
  def separate_with_spleeter(audio_path):
103
  """
104
  Separates an audio file using Spleeter into vocals, drums, bass, other, and piano.
105
+ Uses command-line execution for reliability.
106
  Returns FILE PATHS.
107
  """
108
  if audio_path is None:
109
  return None, None, None, None, None, "Please upload an audio file."
110
 
111
+ if not spleeter_available:
112
+ return None, None, None, None, None, "❌ Spleeter not available. Please install Spleeter."
113
 
114
  try:
115
+ print(f"Spleeter: Processing audio from: {audio_path}")
116
 
117
+ # Create output directory with timestamp
118
+ timestamp = int(time.time() * 1000)
119
+ output_dir = f"spleeter_stems_{timestamp}"
120
+ os.makedirs(output_dir, exist_ok=True)
121
+
122
+ # Run Spleeter command-line tool
123
+ cmd = [
124
+ 'spleeter', 'separate',
125
+ '-i', audio_path,
126
+ '-o', output_dir,
127
+ '-p', 'spleeter:5stems-16kHz'
128
+ ]
129
+
130
+ print(f"Spleeter: Running command: {' '.join(cmd)}")
131
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
132
+
133
+ if result.returncode != 0:
134
+ print(f"Spleeter command failed: {result.stderr}")
135
+ return None, None, None, None, None, f"❌ Spleeter command failed: {result.stderr}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
 
 
 
137
  print("Spleeter: Separation complete.")
 
 
 
 
 
 
 
138
 
139
+ # Find the separated files
140
+ # Spleeter creates a subdirectory with the input filename
141
+ input_filename = os.path.splitext(os.path.basename(audio_path))[0]
142
+ spleeter_output_dir = os.path.join(output_dir, input_filename)
 
 
 
143
 
144
+ if not os.path.exists(spleeter_output_dir):
145
+ print(f"Expected output directory not found: {spleeter_output_dir}")
146
+ return None, None, None, None, None, "❌ Spleeter output directory not found"
147
+
148
+ # Map Spleeter output files to our expected order
149
+ stem_mapping = {
150
+ "vocals": "vocals.wav",
151
+ "drums": "drums.wav",
152
+ "bass": "bass.wav",
153
+ "other": "other.wav",
154
+ "piano": "piano.wav"
155
+ }
156
+
157
+ output_paths = []
158
+ for stem_name, filename in stem_mapping.items():
159
+ source_path = os.path.join(spleeter_output_dir, filename)
160
+ if os.path.exists(source_path):
161
+ # Copy to our timestamped directory for consistency
162
+ dest_path = os.path.join(output_dir, f"{stem_name}_{timestamp}.wav")
163
+ shutil.copy2(source_path, dest_path)
164
+ output_paths.append(dest_path)
165
+ print(f"βœ… Spleeter saved {stem_name} to {dest_path}")
166
  else:
167
+ print(f"⚠️ Warning: {stem_name} file not found: {source_path}")
168
  output_paths.append(None)
169
 
170
+ # Clean up the intermediate directory
171
+ if os.path.exists(spleeter_output_dir):
172
+ shutil.rmtree(spleeter_output_dir)
173
+
174
  return output_paths[0], output_paths[1], output_paths[2], output_paths[3], output_paths[4], "βœ… Spleeter separation successful!"
175
 
176
+ except subprocess.TimeoutExpired:
177
+ return None, None, None, None, None, "❌ Spleeter separation timed out (5 minutes)"
178
  except Exception as e:
179
  print(f"Spleeter Error: {e}")
180
  import traceback
 
234
  print("Creating Gradio interface...")
235
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
236
  gr.Markdown("""
237
+ # 🎡 Music Stem Separator - HT-Demucs & Spleeter 2025
238
 
239
  Upload your music and get stems from both **HT-Demucs** and **Spleeter** models!
240
 
241
  **HT-Demucs** provides: Drums, Bass, Other, Vocals
242
+ **Spleeter 2025** provides: Vocals, Drums, Bass, Other, **Piano** 🎹 (5stems model)
243
 
244
  Compare the quality and choose the best stems for your needs!
245
  """)
 
252
  gr.Markdown("### πŸŽ›οΈ Select Models to Run")
253
  with gr.Row():
254
  htdemucs_toggle = gr.Checkbox(label="🎯 HT-Demucs", value=True, info="Drums, Bass, Other, Vocals")
 
255
  spleeter_toggle = gr.Checkbox(
256
+ label="🎡 Spleeter 2025 (5stems)",
257
+ value=spleeter_available,
258
+ info="Vocals, Drums, Bass, Other, Piano" if spleeter_available else "Not available",
259
+ interactive=spleeter_available
260
  )
261
 
262
  separate_button = gr.Button("πŸš€ Separate Music", variant="primary", size="lg")
 
277
 
278
  # Spleeter Results
279
  with gr.Column():
280
+ gr.Markdown("### 🎡 Spleeter 2025 Results")
281
  with gr.Row():
282
  spleeter_vocals = gr.Audio(label="🎀 Vocals", type="filepath")
283
  spleeter_drums = gr.Audio(label="πŸ₯ Drums", type="filepath")
 
287
  with gr.Row():
288
  spleeter_piano = gr.Audio(label="🎹 Piano", type="filepath")
289
 
290
+ if spleeter_available:
291
+ gr.Markdown("*5stems model: Vocals, Drums, Bass, Other, Piano*")
292
+ else:
293
+ gr.Markdown("*Note: Spleeter 5stems model not available*")
294
 
295
  gr.Markdown("---")
296
 
 
298
  comparison_text = f"""
299
  ### πŸ“‹ Model Comparison
300
 
301
+ | Feature | HT-Demucs | Spleeter 2025 (5stems) |
302
  |---------|-----------|----------|
303
+ | **Vocals** | βœ… High Quality | {'βœ… Available' if spleeter_available else '❌ N/A'} |
304
+ | **Drums** | βœ… High Quality | {'βœ… Available' if spleeter_available else '❌ N/A'} |
305
+ | **Bass** | βœ… High Quality | {'βœ… Available' if spleeter_available else '❌ N/A'} |
306
+ | **Other** | βœ… High Quality | {'βœ… Available' if spleeter_available else '❌ N/A'} |
307
+ | **Piano** | ❌ Not Available | {'βœ… **Available**' if spleeter_available else '❌ N/A'} |
308
+ | **Speed** | ⚑ Fast | {'⚑ Fast' if spleeter_available else '❌ N/A'} |
309
+ | **Quality** | πŸ† Excellent | {'πŸ† Good' if spleeter_available else '❌ N/A'} |
 
310
 
311
+ **πŸ’‘ Tip:** Use Spleeter 2025 for piano separation, HT-Demucs for other instruments!
312
  """
313
  gr.Markdown(comparison_text)
314
 
 
326
  gr.Markdown("""
327
  ---
328
  <p style='text-align: center; font-size: small;'>
329
+ πŸš€ Powered by <strong>HT-Demucs</strong> & <strong>Spleeter 2025</strong> |
330
  🎡 Compare and choose your best stems!
331
  </p>
332
  """)
requirements.txt CHANGED
@@ -3,9 +3,7 @@ spleeter==2.3.2
3
  tensorflow==2.13.0
4
  torch
5
  torchaudio
6
- gradio==3.50.2
7
  numpy>=1.21.0
8
  soundfile
9
- numba==0.55.2
10
- llvmlite==0.38.1
11
- # Use compatible numba and llvmlite versions for Spleeter
 
3
  tensorflow==2.13.0
4
  torch
5
  torchaudio
6
+ gradio==4.44.0
7
  numpy>=1.21.0
8
  soundfile
9
+ librosa