fix: fix mixed up f1, f2

This commit is contained in:
2026-05-17 17:51:24 +02:00
parent 729555acc3
commit 041cba8224
2 changed files with 23 additions and 8 deletions

View File

@@ -169,11 +169,12 @@ class RegularBeatFinder:
def find_beat(self, fs, ssf_zxings, f_hint=None, debug_fe=False, debug_i=None): def find_beat(self, fs, ssf_zxings, f_hint=None, debug_fe=False, debug_i=None):
"""Find the optimal beat frequency.""" """Find the optimal beat frequency."""
act_ibis = np.diff(ssf_zxings) act_ibis = np.diff(ssf_zxings)
# nice-to: may be interesting to also use as score: the ssf amplitude info at the beats to which we aligned
# evaluate mean absolute errors for all frequencies # evaluate mean absolute errors for all frequencies
freqs, freq_errs = self._get_opt_ibi_freq_2(fs, act_ibis, debug_i) freqs, freq_errs = self._get_opt_ibi_freq_2(fs, act_ibis, debug_i)
# bias with f_hint - once we know the beat freq, make it more likely for it to be found everywhere # bias with f_hint - once we know the beat freq, make it more likely for it to be found everywhere
if f_hint is not None: if f_hint is not None:
nf, f1, f2 = RegularBeatFinder.num_freqs, RegularBeatFinder.range_f2, RegularBeatFinder.range_f1 nf, f1, f2 = RegularBeatFinder.num_freqs, RegularBeatFinder.range_f1, RegularBeatFinder.range_f2
bias = gauss( bias = gauss(
nf, nf,
(f_hint - f1) / (f2 - f1) * nf, (f_hint - f1) / (f2 - f1) * nf,

28
song.py
View File

@@ -8,8 +8,9 @@ from sqi import gauss, shift
class SongBeatDetector: class SongBeatDetector:
SEGMENT_SLICE_LEN_SEC = 8.0 #: slice length for processing (long enough to contain bar structure; short enough for a constant freq. beat placement) SEGMENT_SLICE_LEN_SEC = 8.0 #: slice length for processing (long enough to contain bar structure; short enough for a constant freq. beat placement)
SSF_REL_THRES = 1.5 #: optimize for slope of error (mae) function over beat frequency SSF_REL_THRES = 1.5 #: optimize for slope of error (mae) function over beat frequency
NE_THRES = 30.0 #: normalized error threshold for 'good' slices
def __init__(self): pass def __init__(self): pass
def detect(self, fs, sig, debug_fe_idx=None): def detect(self, fs, sig, use_f_hint=True, debug_fe_idx=None):
self.fs = fs self.fs = fs
#self.sig = sig #self.sig = sig
@@ -31,14 +32,27 @@ class SongBeatDetector:
# we segment on 'guitar' info, but process 'bass' later # we segment on 'guitar' info, but process 'bass' later
seg_sl = int(SongBeatDetector.SEGMENT_SLICE_LEN_SEC * fsd) if use_f_hint:
# initial estimate (without 'f_hint')
zds_initial = self._estimate_segments(debug_fe_idx=None)
self.zds_initial = zds_initial
ifbs_good = np.array([zdd['ne'] < SongBeatDetector.NE_THRES for zdd in zds_initial])
fbs = np.array([zdd['fb'] for zdd in zds_initial])[np.where(ifbs_good)[0]]
bins, hfreq = np.histogram(fbs)
ih = np.argmax(bins)
self.f_hint = np.mean((hfreq[ih], hfreq[ih+1])) # center freq of bin
else:
self.f_hint = None
# actual estimate (using 'f_hint' to bias each segment)
self.zds = self._estimate_segments(f_hint=self.f_hint, debug_fe_idx=debug_fe_idx)
self.zds = self._estimate_segments(debug_fe_idx=debug_fe_idx)
return self.zds return self.zds
def _estimate_segments(self, f_hint=None, debug_fe_idx=None): def _estimate_segments(self, f_hint=None, debug_fe_idx=None):
zds = [] zds = []
fsd = self.fsd fsd = self.fsd
seg_sl = int(SongBeatDetector.SEGMENT_SLICE_LEN_SEC * fsd) # segment slice length in 1/fsd units
# for each segment # for each segment
for i in np.arange(self.i_seg.shape[0]-1): for i in np.arange(self.i_seg.shape[0]-1):
i1, i2 = self.i_seg[i], self.i_seg[i+1] i1, i2 = self.i_seg[i], self.i_seg[i+1]
@@ -56,17 +70,16 @@ class SongBeatDetector:
debug_fe = i1 <= debug_fe_sidx < i2 debug_fe = i1 <= debug_fe_sidx < i2
else: else:
debug_fe = False debug_fe = False
zdd = self._process_slice(j1, j2, m, seg_sl, sig_slice, f_hint=f_hint, debug_fe=debug_fe) zdd = self._process_slice(j1, j2, m, sig_slice, f_hint=f_hint, debug_fe=debug_fe)
zds.append(zdd) zds.append(zdd)
return zds return zds
def _process_slice(self, j1, j2, m, seg_sl, sig_slice, f_hint=None, debug_fe=False): def _process_slice(self, j1, j2, m, sig_slice, f_hint=None, debug_fe=False):
""" """
:param j1: lower index into 'sig_slice' :param j1: lower index into 'sig_slice'
:param j2: upper index into 'sig_slice' :param j2: upper index into 'sig_slice'
:param m: slice number (used to check if debugging) :param m: slice number (used to check if debugging)
:param seg_sl: segment slice length in 1/fsd units
:param debug_fe: show plots for SSF and raw/reg beat placement :param debug_fe: show plots for SSF and raw/reg beat placement
""" """
# TODO: C++ impl of SsfZxing._ssf_det_zxings() has diverged. # TODO: C++ impl of SsfZxing._ssf_det_zxings() has diverged.
@@ -75,7 +88,8 @@ class SongBeatDetector:
# - ?? others ?? # - ?? others ??
# NOTE: SsfZxing here is always getting short 8-sec slices only (nb. for 'ssf_th' comput.) # NOTE: SsfZxing here is always getting short 8-sec slices only (nb. for 'ssf_th' comput.)
fsd = self.fsd #: reciprocal window step size fsd = self.fsd # reciprocal window step size
seg_sl = int(SongBeatDetector.SEGMENT_SLICE_LEN_SEC * fsd) # segment slice length in 1/fsd units
SsfZxing.ssf_rel_thres = SongBeatDetector.SSF_REL_THRES SsfZxing.ssf_rel_thres = SongBeatDetector.SSF_REL_THRES
zd = SsfZxing() zd = SsfZxing()