rikhoffbauer2 commited on
Commit
985e22d
·
verified ·
1 Parent(s): b071c80

Fix stem_render function signature and add stem-based analysis"

Browse files
Files changed (1) hide show
  1. stem_render.py +16 -21
stem_render.py CHANGED
@@ -1,30 +1,23 @@
1
- # This file patches render_full_set to use stem-based mixing.
2
- # Import this at the end of app.py or monkey-patch.
3
- # The render_full_set function uses demucs to separate stems,
4
- # then uses stem_mixer.mix_stems for surgical transitions.
5
 
6
- import gradio as gr
7
  import numpy as np
8
  import librosa
9
  import scipy.io.wavfile
10
  import tempfile
11
  import logging
 
12
 
13
  logger = logging.getLogger("dj_engine")
14
 
15
 
16
  def render_full_set_with_stems(app_state, progress=gr.Progress()):
17
- """Render the DJ set using demucs stem separation for surgical mixing.
18
 
19
  Pipeline:
20
- 1. For each track in the set order, run demucs htdemucs to get stems
21
- 2. Pass all stems to stem_mixer.mix_stems which does:
22
- - Beat-aligned placement on a shared timeline
23
- - A's rhythm (drums+bass) stops on a downbeat
24
- - B's rhythm starts on the same downbeat
25
- - Melodic content crossfades smoothly
26
- - Zero simultaneous kicks
27
- 3. Falls back to filter-based mixer if demucs is unavailable
28
  """
29
  if not app_state.transitions:
30
  return None, "⚠️ Generate a set plan first"
@@ -39,7 +32,7 @@ def render_full_set_with_stems(app_state, progress=gr.Progress()):
39
  from stem_mixer import mix_stems
40
 
41
  device = "cuda" if torch.cuda.is_available() else "cpu"
42
- progress(0.03, desc=f"Loading demucs model ({device})...")
43
  model = get_model("htdemucs")
44
  model.eval().to(device)
45
 
@@ -74,25 +67,27 @@ def render_full_set_with_stems(app_state, progress=gr.Progress()):
74
  stems[name] = stem_np
75
 
76
  all_stems[tidx] = stems
77
- logger.info(f"Separated {track.filename}: stems={list(stems.keys())}")
78
 
79
  # Mix using stem mixer
80
- progress(0.55, desc="Mixing with separated stems (surgical drum/bass swap)...")
81
  set_audio, set_info = mix_stems(
82
  all_stems, app_state.analyses, app_state.set_order,
83
  progress_cb=lambda p, m: progress(0.55 + p * 0.35, desc=m)
84
  )
85
- method = "Demucs stem separation → surgical drum/bass swap on downbeats"
86
 
87
  except Exception as e:
88
- logger.warning(f"Stem separation failed: {e}. Using filter-based mixer.")
 
 
89
  from mixer import mix_set
90
- progress(0.10, desc="Falling back to filter-based mixer...")
91
  set_audio, set_info = mix_set(
92
  app_state.analyses, app_state.set_order, app_state.transitions,
93
  progress_cb=lambda p, m: progress(0.10 + p * 0.80, desc=m)
94
  )
95
- method = f"Filter-based mixing (demucs unavailable: {e})"
96
 
97
  app_state.rendered_set = set_audio
98
 
 
1
+ # stem_render.py Stem-based rendering with demucs
2
+ # Called by main.py's patched render_full_set
 
 
3
 
 
4
  import numpy as np
5
  import librosa
6
  import scipy.io.wavfile
7
  import tempfile
8
  import logging
9
+ import gradio as gr
10
 
11
  logger = logging.getLogger("dj_engine")
12
 
13
 
14
  def render_full_set_with_stems(app_state, progress=gr.Progress()):
15
+ """Render the DJ set using demucs stem separation.
16
 
17
  Pipeline:
18
+ 1. Separate each track into stems (drums, bass, vocals, other)
19
+ 2. Analyze stems for better structural understanding
20
+ 3. Mix using stem_mixer for surgical transitions
 
 
 
 
 
21
  """
22
  if not app_state.transitions:
23
  return None, "⚠️ Generate a set plan first"
 
32
  from stem_mixer import mix_stems
33
 
34
  device = "cuda" if torch.cuda.is_available() else "cpu"
35
+ progress(0.03, desc=f"Loading demucs htdemucs ({device})...")
36
  model = get_model("htdemucs")
37
  model.eval().to(device)
38
 
 
67
  stems[name] = stem_np
68
 
69
  all_stems[tidx] = stems
70
+ logger.info(f"Separated {track.filename}: {list(stems.keys())}")
71
 
72
  # Mix using stem mixer
73
+ progress(0.55, desc="Mixing with stems (surgical drum/bass swap)...")
74
  set_audio, set_info = mix_stems(
75
  all_stems, app_state.analyses, app_state.set_order,
76
  progress_cb=lambda p, m: progress(0.55 + p * 0.35, desc=m)
77
  )
78
+ method = "Demucs htdemucs → surgical drum/bass swap on downbeats"
79
 
80
  except Exception as e:
81
+ logger.warning(f"Stem separation failed: {e}. Falling back to filter mixer.")
82
+ import traceback
83
+ traceback.print_exc()
84
  from mixer import mix_set
85
+ progress(0.10, desc="Fallback: filter-based mixing...")
86
  set_audio, set_info = mix_set(
87
  app_state.analyses, app_state.set_order, app_state.transitions,
88
  progress_cb=lambda p, m: progress(0.10 + p * 0.80, desc=m)
89
  )
90
+ method = f"Filter-based (demucs failed: {e})"
91
 
92
  app_state.rendered_set = set_audio
93