-
Notifications
You must be signed in to change notification settings - Fork 0
How it works
AudioWorklet (js/pitch-worklet.js). The main thread never runs NSDF.
- High-pass ~52 Hz, low-pass ~5 kHz (F2 has to survive the low-pass).
- 4096-sample window, pair-averaged to 2048, 55–1350 Hz.
- McLeod NSDF with parabolic interpolation on the peak.
- Harmonic product spectrum snaps a clean octave. It does not veto the frame (that made singing unusable).
- Octave hysteresis so the displayed note does not flip every frame.
- Hold ~420 ms within ±2.4 semitones to auto-save, or tap Save this note. Clarity gate 0.68.
No CREPE / FCPE / ONNX. A neural F0 model is the research SOTA; it is the wrong fit for a CSP-locked GitHub Pages page with no network after first load.
- Range = min and max of saved MIDI notes, not the live needle.
- Tessitura = time-weighted median of those holds.
- Stability = MAD of the holds, in semitones.
Score (semitone distances to each Fach band):
score = 1.3*|rangeLow − f.low|
+ 0.9*|rangeHigh − f.high|
+ 1.1*|tessitura − mid(f)|
Closest type wins. If range and tessitura disagree, the copy says so and follows tessitura. Runners-up are distances plus a relative softmax — not a calibrated probability.
On the same hop, LPC (order 14) estimates F1/F2 and a spectral centroid. A climb of ≥ 8 semitones with a centroid (or H1−H2) jump is the estimated passaggio. Those features tint the score. Vowel still outweighs Fach.
Name, gender, and age are required before the mic. Gender defaults the type filter (male → lower, female → upper). Age changes the explanation (a changing voice is not a finished Fach). Nothing is uploaded.
What is my voice?