From 762f0b7e4e912935dbe0a593b3b3d342aef4fb69 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 01:38:16 +0000 Subject: [PATCH 1/2] fix: pin librosa <0.11 to protect voicing-gate calibration librosa 0.11 changed pyin's voiced decision: white noise scores ~0.43 voiced fraction vs 0.0 on 0.10.x (probed on both versions). Every multi-speaker routing gate (multi_speaker_merge_voiced_min and friends, calibrated leads 0.76-0.87 vs keep-cases 0.14-0.51) was calibrated on 0.10 semantics, so an environment resolving librosa>=0.10 to 0.11 gets a silently mis-calibrated router (and a failing test_multi_speaker_routing noise test). Bound the requirement to the calibrated major, note the coupling in _voiced_fraction, and refresh the requirements-runtime hash in the dependency contract lock (line_count follows the checker's runtime_requirement_count, now 32). Co-Authored-By: claude-flow Claude-Session: https://claude.ai/code/session_01Vqqhm9yzsrG7rgmiMrBjC1 --- requirements-runtime.txt | 6 +++++- requirements.lock | 4 ++-- src/auto_voice/inference/singing_conversion_pipeline.py | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/requirements-runtime.txt b/requirements-runtime.txt index 3d7f2da..8e489df 100644 --- a/requirements-runtime.txt +++ b/requirements-runtime.txt @@ -5,7 +5,11 @@ torch>=2.0 torchaudio>=2.0 numpy>=1.24 scipy>=1.10 -librosa>=0.10 +# <0.11: pyin's voiced decision changed in 0.11 (white noise scores ~0.43 +# voiced vs 0.0 on 0.10), which silently shifts the calibrated multi-speaker +# voicing gates (multi_speaker_merge_voiced_min et al). Re-calibrate before +# raising this bound. +librosa>=0.10,<0.11 soundfile>=0.12 # Web diff --git a/requirements.lock b/requirements.lock index 4c8f1b2..91366c4 100644 --- a/requirements.lock +++ b/requirements.lock @@ -5,8 +5,8 @@ "backend": { "requirements_runtime": { "path": "requirements-runtime.txt", - "sha256": "a2e2fc3c1448ddd6b1caf661daa56a6b37086c36aba586b4e3a2f29a0a916133", - "line_count": 31 + "sha256": "c013d714111e1198048b2a47bbdf7a05b706ae5e5cb05f3686877ed957726f56", + "line_count": 32 }, "frontend_lock": { "path": "frontend/package-lock.json", diff --git a/src/auto_voice/inference/singing_conversion_pipeline.py b/src/auto_voice/inference/singing_conversion_pipeline.py index 495834e..9927539 100644 --- a/src/auto_voice/inference/singing_conversion_pipeline.py +++ b/src/auto_voice/inference/singing_conversion_pipeline.py @@ -44,6 +44,10 @@ def _voiced_fraction(audio: np.ndarray, sample_rate: int, max_s: float = 20.0) - (calibrated leads: 0.76-0.87); harmony stacks / textures it would butcher score low (calibrated: 0.14-0.51). Measured on up to ``max_s`` of active audio with pyin fmin=80 fmax=1000, matching the calibration convention. + + Calibration is coupled to librosa 0.10 pyin semantics (0.11 changed the + voiced decision: white noise jumps from 0.0 to ~0.43) — hence the + ``librosa<0.11`` bound in requirements-runtime.txt. """ import librosa From a4b67eb37bef7e3ed5ceb51d3091b59b64be9f14 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 01:38:16 +0000 Subject: [PATCH 2/2] fix: accept method kwarg in fork HQ lane _extract_pitch stub The quality-tiers change made _convert_song_fork_hq pass method=q['f0_method'] to _extract_pitch, but the test's monkeypatched lambda still had the old (audio, sr) signature, so test_fork_hq_lane_is_stereo_and_mirrors_contract failed at HEAD with a TypeError. Mirror the real signature's optional kwarg in the stub. Co-Authored-By: claude-flow Claude-Session: https://claude.ai/code/session_01Vqqhm9yzsrG7rgmiMrBjC1 --- tests/test_fork_hq_lane.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_fork_hq_lane.py b/tests/test_fork_hq_lane.py index 256da95..e23a575 100644 --- a/tests/test_fork_hq_lane.py +++ b/tests/test_fork_hq_lane.py @@ -33,7 +33,8 @@ def infer(self, audio, spk, emb, sr): monkeypatch.setattr(p, "_get_separator", lambda: FakeSep()) monkeypatch.setattr(p, "_get_model_manager", lambda: FakeMM()) - monkeypatch.setattr(p, "_extract_pitch", lambda a, sr: np.zeros(8, np.float32)) + monkeypatch.setattr(p, "_extract_pitch", + lambda a, sr, method=None: np.zeros(8, np.float32)) res = p._convert_song_fork_hq(str(song), "prof-1", 1.0, 0.9, True, "balanced", 0.0)