rikhoffbauer2 commited on
Commit
7f4584f
Β·
verified Β·
1 Parent(s): ca47278

hotfix: patch _sf() kwarg bug at import time"

Browse files
Files changed (1) hide show
  1. app.py +38 -46
app.py CHANGED
@@ -3,14 +3,25 @@ Gradio UI β€” Sample Extractor v9.
3
  SuperFlux onsets, transient NCC, mel pre-filter, MIDI quantization, param locking.
4
  """
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  import gradio as gr
7
- import numpy as np, pandas as pd, json, sys, os, tempfile
8
  import soundfile as sf, librosa
9
  import matplotlib; matplotlib.use('Agg')
10
  import matplotlib.pyplot as plt
11
 
12
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
13
-
14
  from sample_extractor import (
15
  extract_stem, detect_onsets, classify_hits,
16
  cluster_hits, select_best, synthesize_from_cluster,
@@ -78,14 +89,14 @@ def run_extraction(audio_in, stem_choice, demucs_model, demucs_shifts, demucs_ov
78
  sa,ssr=extract_stem(tmp,stem=stem_choice,device="cpu",
79
  model_name=demucs_model,shifts=int(demucs_shifts),overlap=float(demucs_overlap))
80
  progress(0.15,desc="BPM..."); bpm=detect_bpm(sa,ssr)
81
- progress(0.25,desc="Onsets (SuperFlux)...")
82
  hits=detect_onsets(sa,ssr,mode=onset_mode,onset_delta=float(onset_delta),
83
  energy_threshold_db=float(energy_db),pre_pad=float(pre_pad),
84
  min_dur=float(min_dur),max_dur=float(max_dur),min_gap=float(min_gap))
85
  if not hits:
86
  return (audio_tuple(sa,ssr),f"**BPM: {bpm}** β€” No hits.",None,None,None,None,"",pd.DataFrame())
87
  progress(0.35,desc="Classify..."); hits=classify_hits(hits)
88
- progress(0.45,desc="Cluster (transient NCC)...")
89
  cl=cluster_hits(hits,audio=sa,sr=ssr,ncc_threshold=float(ncc_threshold),
90
  attack_ms=float(attack_ms),target_min=int(target_min),target_max=int(target_max),linkage=str(linkage))
91
  progress(0.65,desc="Select..."); select_best(cl)
@@ -112,7 +123,7 @@ def run_extraction(audio_in, stem_choice, demucs_model, demucs_shifts, demucs_ov
112
  sm=f"**BPM: {bpm}** Β· **{len(cl)} samples** from {len(hits)} hits\n\n"
113
  sm+=f"`{demucs_model}` Β· Ξ΄=`{onset_delta}` Β· E=`{energy_db}dB` Β· attack=`{attack_ms}ms`"
114
  if int(target_min)>0 and int(target_max)>0: sm+=f" Β· clusters `{int(target_min)}–{int(target_max)}`"
115
- if quantize_midi: sm+=f" Β· MIDI quantized to 1/{int(subdivision)}"
116
  sm+="\n\n| Sample | Hits | MIDI |\n|---|---|---|\n"
117
  for c in sorted(cl,key=lambda x:x.count,reverse=True): sm+=f"| {c.label} | {c.count} | {c.midi_note} |\n"
118
  progress(1.0)
@@ -162,57 +173,47 @@ def build_app():
162
  with gr.Blocks(title="🎡 Sample Extractor",theme=gr.themes.Soft(),
163
  css=".gradio-container{max-width:1300px!important}") as app:
164
  gr.Markdown("# 🎡 Sample Extractor v9\n"
165
- "**SuperFlux** onset detection Β· **Transient NCC** clustering (25ms attack matching) Β· "
166
  "**Mel pre-filter** Β· **MIDI quantization** Β· **Auto-Tune** with πŸ”’ locks")
167
-
168
  with gr.Tabs():
169
  with gr.Tab("🎡 Extract"):
170
  audio_in=gr.Audio(sources=['upload'],type='numpy',label='Upload Audio')
171
-
172
  with gr.Accordion("πŸ”§ Stem Separation",open=False):
173
  with gr.Row():
174
  dm=gr.Dropdown(DEMUCS_MODELS,value="htdemucs_ft",label="Model")
175
  st=gr.Dropdown(['drums','bass','other','vocals','all'],value='drums',label='Stem')
176
  dsh=gr.Slider(0,5,value=1,step=1,label='Shifts')
177
  dov=gr.Slider(0.0,0.5,value=0.25,step=0.05,label='Overlap')
178
-
179
- with gr.Accordion("🎯 Onset Detection (SuperFlux)",open=False):
180
  with gr.Row(): om=gr.Dropdown(['auto','percussive','harmonic','broadband'],value='auto',label='Mode')
181
  with gr.Row():
182
- od=gr.Slider(0.01,0.5,value=0.12,step=0.01,label='Delta')
183
- lock_od=gr.Checkbox(value=False,label='πŸ”’',scale=0)
184
  with gr.Row():
185
- ed=gr.Slider(-70,-10,value=-35,step=1,label='Energy (dB)')
186
- lock_ed=gr.Checkbox(value=False,label='πŸ”’',scale=0)
187
  with gr.Row():
188
- mg=gr.Slider(0.005,0.2,value=0.03,step=0.005,label='Min gap (s)')
189
- lock_mg=gr.Checkbox(value=False,label='πŸ”’',scale=0)
190
  with gr.Row():
191
- pp=gr.Slider(0.0,0.05,value=0.003,step=0.001,label='Pre-pad (s)')
192
- mnd=gr.Slider(0.005,0.2,value=0.02,step=0.005,label='Min dur (s)')
193
- mxd=gr.Slider(0.1,5.0,value=1.5,step=0.1,label='Max dur (s)')
194
-
195
- with gr.Accordion("πŸ”— Clustering (Transient NCC + Mel pre-filter)",open=True):
196
  with gr.Row():
197
  tmin=gr.Number(value=5,label='Target min',precision=0)
198
  tmax=gr.Number(value=20,label='Target max',precision=0)
199
  lock_tgt=gr.Checkbox(value=True,label='πŸ”’ Lock range',scale=0)
200
- gr.Markdown("*πŸ”’ = auto-tune respects this value*")
201
  with gr.Row():
202
  nt=gr.Slider(0.3,0.99,value=0.80,step=0.01,label='NCC threshold')
203
- atk=gr.Slider(10,100,value=25,step=5,label='Attack window (ms)')
204
  lnk=gr.Dropdown(['average','complete','single'],value='average',label='Linkage')
205
-
206
- with gr.Accordion("🎹 MIDI & Post-processing",open=False):
207
  with gr.Row():
208
- syn=gr.Checkbox(value=True,label='Synthesize samples')
209
  qmidi=gr.Checkbox(value=True,label='Quantize MIDI')
210
  subdiv=gr.Dropdown([('8th',8),('16th',16),('32nd',32)],value=16,label='Grid')
211
-
212
  with gr.Row():
213
  tune_btn=gr.Button("πŸŽ›οΈ Auto-Tune",variant="secondary",size="lg")
214
  extract_btn=gr.Button("πŸ”¬ Extract",variant="primary",size="lg")
215
-
216
  tune_summary=gr.Markdown(""); tune_log=gr.Textbox(label="Log",lines=8,max_lines=15,visible=False)
217
  summary_md=gr.Markdown("*Upload β†’ Auto-Tune or Extract*")
218
  with gr.Row():
@@ -220,24 +221,18 @@ def build_app():
220
  rend_out=gr.Audio(type='numpy',label='πŸ”Š Reconstruction',interactive=False)
221
  gr.Markdown("### Downloads")
222
  with gr.Row():
223
- arc=gr.File(label="πŸ“¦ ZIP",interactive=False)
224
- mid=gr.File(label="🎹 MIDI",interactive=False)
225
  smp=gr.File(label="WAVs",file_count="multiple",interactive=False)
226
  met=gr.Dataframe(label="Samples"); stx=gr.Textbox(visible=False)
227
-
228
- dm.change(fn=lambda m:gr.update(choices=DEMUCS_STEMS.get(m,["drums","bass","other","vocals"])+["all"]),
229
- inputs=[dm],outputs=[st])
230
  tune_btn.click(run_auto_tune,[audio_in,st,dm,dsh,dov,om,od,ed,mg,tmin,tmax,lock_od,lock_ed,lock_mg,lock_tgt],
231
  [od,ed,mg,tmin,tmax,tune_summary,tune_log])
232
- extract_btn.click(run_extraction,
233
- [audio_in,st,dm,dsh,dov,om,od,ed,pp,mnd,mxd,mg,nt,atk,lnk,tmin,tmax,syn,qmidi,subdiv],
234
  [stem_out,summary_md,rend_out,smp,mid,arc,stx,met])
235
-
236
  with gr.Tab("πŸ“Š Evaluate"):
237
  with gr.Row():
238
  ep=gr.Dropdown(['rock','funk','halftime'],value='rock',label='Pattern')
239
- eb=gr.Slider(80,200,value=120,step=2,label='BPM')
240
- ebs=gr.Slider(2,8,value=4,step=1,label='Bars')
241
  with gr.Row():
242
  en=gr.Slider(0.3,0.99,value=0.80,step=0.01,label='NCC')
243
  etm=gr.Number(value=0,label='Min',precision=0); etx=gr.Number(value=0,label='Max',precision=0)
@@ -248,17 +243,14 @@ def build_app():
248
  evs=gr.Dataframe(); evm2=gr.Dataframe()
249
  es1=gr.Textbox(visible=False); es2=gr.Textbox(visible=False)
250
  evb.click(run_eval,[ep,eb,ebs,en,etm,etx],[evm,evr,evs,evm2,es1,es2])
251
-
252
  with gr.Tab("πŸ”„ Optimize"):
253
  with gr.Row():
254
- on=gr.Slider(2,30,value=5,step=1,label='Iters')
255
- ocn=gr.Textbox(value="opt",label='Name'); oa=gr.Textbox(value="",label='Author')
256
- osv=gr.Checkbox(value=True,label='Save')
257
  ob=gr.Button("πŸš€ Run",variant="primary",size="lg")
258
- ol=gr.Textbox(label="Log",lines=20,max_lines=40)
259
- oh=gr.Dataframe(); op=gr.Plot(); oc=gr.Code(label="Config",language="json")
260
  ob.click(run_optimize,[on,ocn,oa,osv],[ol,oh,op,oc])
261
-
262
  with gr.Tab("πŸ† Leaderboard"):
263
  lbb=gr.Button("πŸ”„ Refresh"); lt=gr.Dataframe(); ls=gr.Textbox(visible=False)
264
  lbb.click(refresh_lb,[],[lt,ls])
 
3
  SuperFlux onsets, transient NCC, mel pre-filter, MIDI quantization, param locking.
4
  """
5
 
6
+ import os, sys
7
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
8
+
9
+ # ─── HOTFIX: patch _sf() keyword argument bug ────────────────────────────────
10
+ _src = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'sample_extractor.py')
11
+ with open(_src, 'r') as _f: _content = _f.read()
12
+ if '_sf(yh,lag=2,ms=5)' in _content:
13
+ _content = _content.replace('_sf(yh,lag=2,ms=5)', '_sf(yh,l=2,ms=5)')
14
+ with open(_src, 'w') as _f: _f.write(_content)
15
+ print("[HOTFIX] Fixed _sf() kwarg: lag=2 β†’ l=2")
16
+ del _src, _content
17
+ # ──────────────────────────────────────────────────────────────────────────────
18
+
19
  import gradio as gr
20
+ import numpy as np, pandas as pd, json, tempfile
21
  import soundfile as sf, librosa
22
  import matplotlib; matplotlib.use('Agg')
23
  import matplotlib.pyplot as plt
24
 
 
 
25
  from sample_extractor import (
26
  extract_stem, detect_onsets, classify_hits,
27
  cluster_hits, select_best, synthesize_from_cluster,
 
89
  sa,ssr=extract_stem(tmp,stem=stem_choice,device="cpu",
90
  model_name=demucs_model,shifts=int(demucs_shifts),overlap=float(demucs_overlap))
91
  progress(0.15,desc="BPM..."); bpm=detect_bpm(sa,ssr)
92
+ progress(0.25,desc="Onsets...")
93
  hits=detect_onsets(sa,ssr,mode=onset_mode,onset_delta=float(onset_delta),
94
  energy_threshold_db=float(energy_db),pre_pad=float(pre_pad),
95
  min_dur=float(min_dur),max_dur=float(max_dur),min_gap=float(min_gap))
96
  if not hits:
97
  return (audio_tuple(sa,ssr),f"**BPM: {bpm}** β€” No hits.",None,None,None,None,"",pd.DataFrame())
98
  progress(0.35,desc="Classify..."); hits=classify_hits(hits)
99
+ progress(0.45,desc="Cluster...")
100
  cl=cluster_hits(hits,audio=sa,sr=ssr,ncc_threshold=float(ncc_threshold),
101
  attack_ms=float(attack_ms),target_min=int(target_min),target_max=int(target_max),linkage=str(linkage))
102
  progress(0.65,desc="Select..."); select_best(cl)
 
123
  sm=f"**BPM: {bpm}** Β· **{len(cl)} samples** from {len(hits)} hits\n\n"
124
  sm+=f"`{demucs_model}` Β· Ξ΄=`{onset_delta}` Β· E=`{energy_db}dB` Β· attack=`{attack_ms}ms`"
125
  if int(target_min)>0 and int(target_max)>0: sm+=f" Β· clusters `{int(target_min)}–{int(target_max)}`"
126
+ if quantize_midi: sm+=f" Β· MIDI 1/{int(subdivision)}"
127
  sm+="\n\n| Sample | Hits | MIDI |\n|---|---|---|\n"
128
  for c in sorted(cl,key=lambda x:x.count,reverse=True): sm+=f"| {c.label} | {c.count} | {c.midi_note} |\n"
129
  progress(1.0)
 
173
  with gr.Blocks(title="🎡 Sample Extractor",theme=gr.themes.Soft(),
174
  css=".gradio-container{max-width:1300px!important}") as app:
175
  gr.Markdown("# 🎡 Sample Extractor v9\n"
176
+ "**SuperFlux** onsets Β· **Transient NCC** (25ms attack) Β· "
177
  "**Mel pre-filter** Β· **MIDI quantization** Β· **Auto-Tune** with πŸ”’ locks")
 
178
  with gr.Tabs():
179
  with gr.Tab("🎡 Extract"):
180
  audio_in=gr.Audio(sources=['upload'],type='numpy',label='Upload Audio')
 
181
  with gr.Accordion("πŸ”§ Stem Separation",open=False):
182
  with gr.Row():
183
  dm=gr.Dropdown(DEMUCS_MODELS,value="htdemucs_ft",label="Model")
184
  st=gr.Dropdown(['drums','bass','other','vocals','all'],value='drums',label='Stem')
185
  dsh=gr.Slider(0,5,value=1,step=1,label='Shifts')
186
  dov=gr.Slider(0.0,0.5,value=0.25,step=0.05,label='Overlap')
187
+ with gr.Accordion("🎯 Onset Detection",open=False):
 
188
  with gr.Row(): om=gr.Dropdown(['auto','percussive','harmonic','broadband'],value='auto',label='Mode')
189
  with gr.Row():
190
+ od=gr.Slider(0.01,0.5,value=0.12,step=0.01,label='Delta'); lock_od=gr.Checkbox(value=False,label='πŸ”’',scale=0)
 
191
  with gr.Row():
192
+ ed=gr.Slider(-70,-10,value=-35,step=1,label='Energy (dB)'); lock_ed=gr.Checkbox(value=False,label='πŸ”’',scale=0)
 
193
  with gr.Row():
194
+ mg=gr.Slider(0.005,0.2,value=0.03,step=0.005,label='Min gap'); lock_mg=gr.Checkbox(value=False,label='πŸ”’',scale=0)
 
195
  with gr.Row():
196
+ pp=gr.Slider(0.0,0.05,value=0.003,step=0.001,label='Pre-pad')
197
+ mnd=gr.Slider(0.005,0.2,value=0.02,step=0.005,label='Min dur')
198
+ mxd=gr.Slider(0.1,5.0,value=1.5,step=0.1,label='Max dur')
199
+ with gr.Accordion("πŸ”— Clustering",open=True):
 
200
  with gr.Row():
201
  tmin=gr.Number(value=5,label='Target min',precision=0)
202
  tmax=gr.Number(value=20,label='Target max',precision=0)
203
  lock_tgt=gr.Checkbox(value=True,label='πŸ”’ Lock range',scale=0)
204
+ gr.Markdown("*πŸ”’ = auto-tune keeps this value fixed*")
205
  with gr.Row():
206
  nt=gr.Slider(0.3,0.99,value=0.80,step=0.01,label='NCC threshold')
207
+ atk=gr.Slider(10,100,value=25,step=5,label='Attack (ms)')
208
  lnk=gr.Dropdown(['average','complete','single'],value='average',label='Linkage')
209
+ with gr.Accordion("🎹 MIDI & Post",open=False):
 
210
  with gr.Row():
211
+ syn=gr.Checkbox(value=True,label='Synthesize')
212
  qmidi=gr.Checkbox(value=True,label='Quantize MIDI')
213
  subdiv=gr.Dropdown([('8th',8),('16th',16),('32nd',32)],value=16,label='Grid')
 
214
  with gr.Row():
215
  tune_btn=gr.Button("πŸŽ›οΈ Auto-Tune",variant="secondary",size="lg")
216
  extract_btn=gr.Button("πŸ”¬ Extract",variant="primary",size="lg")
 
217
  tune_summary=gr.Markdown(""); tune_log=gr.Textbox(label="Log",lines=8,max_lines=15,visible=False)
218
  summary_md=gr.Markdown("*Upload β†’ Auto-Tune or Extract*")
219
  with gr.Row():
 
221
  rend_out=gr.Audio(type='numpy',label='πŸ”Š Reconstruction',interactive=False)
222
  gr.Markdown("### Downloads")
223
  with gr.Row():
224
+ arc=gr.File(label="πŸ“¦ ZIP",interactive=False); mid=gr.File(label="🎹 MIDI",interactive=False)
 
225
  smp=gr.File(label="WAVs",file_count="multiple",interactive=False)
226
  met=gr.Dataframe(label="Samples"); stx=gr.Textbox(visible=False)
227
+ dm.change(fn=lambda m:gr.update(choices=DEMUCS_STEMS.get(m,["drums","bass","other","vocals"])+["all"]),inputs=[dm],outputs=[st])
 
 
228
  tune_btn.click(run_auto_tune,[audio_in,st,dm,dsh,dov,om,od,ed,mg,tmin,tmax,lock_od,lock_ed,lock_mg,lock_tgt],
229
  [od,ed,mg,tmin,tmax,tune_summary,tune_log])
230
+ extract_btn.click(run_extraction,[audio_in,st,dm,dsh,dov,om,od,ed,pp,mnd,mxd,mg,nt,atk,lnk,tmin,tmax,syn,qmidi,subdiv],
 
231
  [stem_out,summary_md,rend_out,smp,mid,arc,stx,met])
 
232
  with gr.Tab("πŸ“Š Evaluate"):
233
  with gr.Row():
234
  ep=gr.Dropdown(['rock','funk','halftime'],value='rock',label='Pattern')
235
+ eb=gr.Slider(80,200,value=120,step=2,label='BPM'); ebs=gr.Slider(2,8,value=4,step=1,label='Bars')
 
236
  with gr.Row():
237
  en=gr.Slider(0.3,0.99,value=0.80,step=0.01,label='NCC')
238
  etm=gr.Number(value=0,label='Min',precision=0); etx=gr.Number(value=0,label='Max',precision=0)
 
243
  evs=gr.Dataframe(); evm2=gr.Dataframe()
244
  es1=gr.Textbox(visible=False); es2=gr.Textbox(visible=False)
245
  evb.click(run_eval,[ep,eb,ebs,en,etm,etx],[evm,evr,evs,evm2,es1,es2])
 
246
  with gr.Tab("πŸ”„ Optimize"):
247
  with gr.Row():
248
+ on=gr.Slider(2,30,value=5,step=1,label='Iters'); ocn=gr.Textbox(value="opt",label='Name')
249
+ oa=gr.Textbox(value="",label='Author'); osv=gr.Checkbox(value=True,label='Save')
 
250
  ob=gr.Button("πŸš€ Run",variant="primary",size="lg")
251
+ ol=gr.Textbox(label="Log",lines=20,max_lines=40); oh=gr.Dataframe(); op=gr.Plot()
252
+ oc=gr.Code(label="Config",language="json")
253
  ob.click(run_optimize,[on,ocn,oa,osv],[ol,oh,op,oc])
 
254
  with gr.Tab("πŸ† Leaderboard"):
255
  lbb=gr.Button("πŸ”„ Refresh"); lt=gr.Dataframe(); ls=gr.Textbox(visible=False)
256
  lbb.click(refresh_lb,[],[lt,ls])