"""Dominant partials (0.3 to 1.5 s after the onset) of several clips, side by side. Usage: python3 partials.py CLIP.wav|CLIP.f32 ... """ import sys, wave, numpy as np from scipy.signal import find_peaks FS = 48000 def load(p): if p.endswith(".f32"): return np.fromfile(p, dtype=" 0.3 * e.max())) - int(0.005 * FS)) def partials(x, a=0.3, b=1.5, fmin=100, fmax=1300, n=12): s = x[int(a * FS):int(b * FS)] S = 20 * np.log10(np.abs(np.fft.rfft(s * np.hanning(len(s)))) + 1e-12) f = np.fft.rfftfreq(len(s), 1 / FS) m = (f > fmin) & (f < fmax) S = S - S[m].max() idx, _ = find_peaks(S, prominence=8, distance=int(3 / (FS / len(s)))) idx = [i for i in idx if m[i]] idx = sorted(idx, key=lambda i: -S[i])[:n] return " ".join(f"{f[i]:.0f}({S[i]:.0f})" for i in sorted(idx)) for p in sys.argv[1:]: x = load(p) x = x[onset(x):] print(f"{p:36s} {partials(x)}")