pitch: treat bleed in the vocal stem as silence #15

Merged
branderson merged 1 commits from pitch-silence into main 2026-10-09 18:15:22 -07:00
Collaborator

Summary generated by LLM agent

Charts could fill an instrumental break with a run of ~ notes when a sung word's alignment stretched into the break.

Cause

The separated vocal stem isn't truly silent during instrumental passages: faint bleed remains, at around -60 dB A-weighted. crepe still finds a pitch in it, and 14–44% of those frames had periodicity of at least 0.5, so they passed the notes stage's voicing mask. When the forced aligner stretched a word's end across such a gap, every one of those frames became a note.

Fix

track_pitch now zeroes the confidence of frames more than 25 dB below the song's 90th-percentile A-weighted loudness (torchcrepe.loudness.a_weighted, the same measure torchcrepe.threshold.Silence uses). The threshold is relative so that it holds however loud the song was mastered. The README's fixed -60 dB only caught 18% of the bleed frames on the test song, because the bleed sat right at that level.

Existing songs can be fixed by rebuilding with Restart from set to pitch.

Testing

  • Unit tests check that bleed is muted, quiet singing is kept, and the threshold follows the song's own level.
  • I ran the real pitch and notes stages twice on CPU on a song from the user's library, once with the gate and once without, against the same alignment. Notes inside an 8s instrumental gap went from 10 to 1, and the total from 691 to 679. Elsewhere the counts changed by at most one note per 10s window. Only 0.3% of voiced frames inside aligned words were muted.
  • Full suite passes, except test_cli.py::test_version (needs the package installed) and the intermittent test_web.py failures that also happen on main.
**Summary generated by LLM agent** Charts could fill an instrumental break with a run of `~` notes when a sung word's alignment stretched into the break. ## Cause The separated vocal stem isn't truly silent during instrumental passages: faint bleed remains, at around -60 dB A-weighted. crepe still finds a pitch in it, and 14–44% of those frames had periodicity of at least 0.5, so they passed the notes stage's voicing mask. When the forced aligner stretched a word's end across such a gap, every one of those frames became a note. ## Fix `track_pitch` now zeroes the confidence of frames more than 25 dB below the song's 90th-percentile A-weighted loudness (`torchcrepe.loudness.a_weighted`, the same measure `torchcrepe.threshold.Silence` uses). The threshold is relative so that it holds however loud the song was mastered. The README's fixed -60 dB only caught 18% of the bleed frames on the test song, because the bleed sat right at that level. Existing songs can be fixed by rebuilding with **Restart from** set to `pitch`. ## Testing - Unit tests check that bleed is muted, quiet singing is kept, and the threshold follows the song's own level. - I ran the real pitch and notes stages twice on CPU on a song from the user's library, once with the gate and once without, against the same alignment. Notes inside an 8s instrumental gap went from 10 to 1, and the total from 691 to 679. Elsewhere the counts changed by at most one note per 10s window. Only 0.3% of voiced frames inside aligned words were muted. - Full suite passes, except `test_cli.py::test_version` (needs the package installed) and the intermittent `test_web.py` failures that also happen on `main`.
dejima-agent added 1 commit 2026-10-09 18:06:34 -07:00
Separated stems keep faint bleed during instrumental passages, and crepe
finds a pitch in it with enough confidence to pass the voicing mask. A word
whose alignment ran into such a gap was then filled with notes for the
whole gap. Zero the confidence of frames more than 25 dB below the song's
90th-percentile A-weighted loudness, relative so it holds at any mastering
level.
branderson approved these changes 2026-10-09 18:15:17 -07:00
branderson merged commit ec78f18d17 into main 2026-10-09 18:15:22 -07:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: branderson/songtrace#15