JacobLinCool commited on
Commit
b0c1209
·
verified ·
1 Parent(s): c920743

Fixed-BPM grid + piecewise fit + dual-mode support

Browse files
Files changed (1) hide show
  1. app.py +10 -4
app.py CHANGED
@@ -15,7 +15,7 @@ import numpy as np
15
  import torch
16
 
17
  from softchart.generate import generate_song, generate_song_slot, load_hf
18
- from softchart.grid import debias_to_grid, fit_grid
19
  from softchart.hf import SoftChartPlanner
20
  from softchart.rhythm import snap_chart
21
  from softchart.tja import write_tja_slots
@@ -246,7 +246,7 @@ def generate(audio, course, level, bpm_override, auto_plan_on, use_beat, use_pla
246
  if use_beat and M["beat"] is not None:
247
  # global robust (period, phase) fit over the whole song — much more
248
  # precise than per-peak use (each raw peak carries ~±23 ms bin noise)
249
- grid = fit_grid(M["beat"], mel, device=DEVICE)
250
  if grid is not None:
251
  # rigid synthesized barlines when the fit is trustworthy; raw peaks
252
  # (plan-block edges only, no anchoring) when it is not
@@ -255,8 +255,13 @@ def generate(audio, course, level, bpm_override, auto_plan_on, use_beat, use_pla
255
  grid = None
256
  if bpm_override and bpm_override > 0:
257
  bpm = float(bpm_override)
258
- if grid is not None and abs(grid["bpm"] - bpm) > 0.5:
259
- grid = None # user disagrees with the fit: don't anchor to it
 
 
 
 
 
260
  elif grid is not None:
261
  bpm = grid["bpm"] # already integer-snapped when the residual allows
262
  elif dbs is not None and len(dbs) > 4:
@@ -301,6 +306,7 @@ def generate(audio, course, level, bpm_override, auto_plan_on, use_beat, use_pla
301
  img = render(mel, g, title, course)
302
  if grid is not None:
303
  grid_info = (f" · grid: rms {grid['rms_ms']:.1f}ms ({grid['inlier_frac']:.0%} inlier)"
 
304
  + (" · slot-exact" if slot_used else ""))
305
  elif use_beat and M["beat"] is not None:
306
  grid_info = " · grid: unreliable, barline anchoring off"
 
15
  import torch
16
 
17
  from softchart.generate import generate_song, generate_song_slot, load_hf
18
+ from softchart.grid import debias_to_grid, fit_grid_fixed_bpm, fit_grid_piecewise
19
  from softchart.hf import SoftChartPlanner
20
  from softchart.rhythm import snap_chart
21
  from softchart.tja import write_tja_slots
 
246
  if use_beat and M["beat"] is not None:
247
  # global robust (period, phase) fit over the whole song — much more
248
  # precise than per-peak use (each raw peak carries ~±23 ms bin noise)
249
+ grid = fit_grid_piecewise(M["beat"], mel, device=DEVICE)
250
  if grid is not None:
251
  # rigid synthesized barlines when the fit is trustworthy; raw peaks
252
  # (plan-block edges only, no anchoring) when it is not
 
255
  grid = None
256
  if bpm_override and bpm_override > 0:
257
  bpm = float(bpm_override)
258
+ if use_beat and M["beat"] is not None and (grid is None or abs(grid["bpm"] - bpm) > 0.5):
259
+ # the user KNOWS the tempo: phase-only fit with a trusted period —
260
+ # much easier than the free fit, often unlocks the slot-exact path
261
+ g2 = fit_grid_fixed_bpm(M["beat"], mel, bpm, device=DEVICE)
262
+ grid = g2 if (g2 is not None and g2["ok"]) else None
263
+ if grid is not None:
264
+ dbs = grid["downbeats"]
265
  elif grid is not None:
266
  bpm = grid["bpm"] # already integer-snapped when the residual allows
267
  elif dbs is not None and len(dbs) > 4:
 
306
  img = render(mel, g, title, course)
307
  if grid is not None:
308
  grid_info = (f" · grid: rms {grid['rms_ms']:.1f}ms ({grid['inlier_frac']:.0%} inlier)"
309
+ + (f" · {grid['n_segments']} tempo segs" if grid.get("piecewise") else "")
310
  + (" · slot-exact" if slot_used else ""))
311
  elif use_beat and M["beat"] is not None:
312
  grid_info = " · grid: unreliable, barline anchoring off"