mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-15 12:50:42 -07:00
fix(audio): raise trim threshold, cap pad at net-neutral
Review feedback on the preprocessor: 1. ``trim_top_db=30`` was labelled "conservative" in the docstring but is actually *more* aggressive than librosa's default of 60. Normal speech dynamic range sits around 30 dB, so 30 dB would eat quiet trailing syllables and soft consonants. Raise the default to 40 dB — below normal speech dynamic range but still catching obvious edge silence — and fix the docstring. 2. Unconditional 100 ms edge padding ran even when ``librosa.effects.trim`` removed nothing. For a well-recorded 29.9 s upload that path would push the waveform past the 30 s ceiling and trigger a spurious "too long" rejection. Only pad when trimming actually shortened the audio, and cap the pad so the output never exceeds the input length. Adds a regression test for the net-neutral length behaviour. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
a49cc6afbb
commit
4ffbc03d15
@@ -58,6 +58,15 @@ def test_silence_is_trimmed_with_padding_kept():
|
||||
assert len(out) >= int(3.0 * SR), "speech body should be preserved"
|
||||
|
||||
|
||||
def test_clean_audio_is_not_padded_past_original_length():
|
||||
# Well-recorded audio with no edge silence shouldn't get longer after
|
||||
# preprocessing — otherwise a 29.9 s upload could be pushed past the
|
||||
# 30 s max_duration ceiling downstream.
|
||||
audio = _tone(3.0, amp=0.3)
|
||||
out = preprocess_reference_audio(audio, SR)
|
||||
assert len(out) <= len(audio)
|
||||
|
||||
|
||||
def test_empty_input_returns_empty():
|
||||
out = preprocess_reference_audio(np.zeros(0, dtype=np.float32), SR)
|
||||
assert out.size == 0
|
||||
|
||||
+16
-6
@@ -203,7 +203,7 @@ def preprocess_reference_audio(
|
||||
audio: np.ndarray,
|
||||
sample_rate: int,
|
||||
peak_target: float = 0.95,
|
||||
trim_top_db: float = 30.0,
|
||||
trim_top_db: float = 40.0,
|
||||
edge_padding_ms: int = 100,
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
@@ -221,9 +221,14 @@ def preprocess_reference_audio(
|
||||
peak_target: Peak amplitude cap in [0, 1]. Applied only if the input
|
||||
peak exceeds this value.
|
||||
trim_top_db: Silence threshold for edge trimming, in dB below peak.
|
||||
Conservative (30 dB) so soft speech at the edges isn't clipped off.
|
||||
edge_padding_ms: Milliseconds of padding retained at each edge after
|
||||
trimming, so TTS engines have a brief silence to anchor on.
|
||||
40 dB sits below normal speech dynamic range (≈30 dB) so soft
|
||||
trailing syllables are preserved, while still catching obvious
|
||||
leading/trailing silence. Lower values are more aggressive;
|
||||
librosa's own default is 60.
|
||||
edge_padding_ms: Milliseconds of padding to add back at each edge
|
||||
*only if* trimming shortened the waveform, so TTS engines have a
|
||||
brief silence to anchor on without ever making the output longer
|
||||
than the input.
|
||||
|
||||
Returns:
|
||||
Preprocessed audio array (float32).
|
||||
@@ -236,8 +241,13 @@ def preprocess_reference_audio(
|
||||
audio = audio - float(np.mean(audio))
|
||||
|
||||
trimmed, _ = librosa.effects.trim(audio, top_db=trim_top_db)
|
||||
if trimmed.size > 0:
|
||||
pad = int(sample_rate * edge_padding_ms / 1000)
|
||||
if 0 < trimmed.size < audio.size:
|
||||
pad_each = int(sample_rate * edge_padding_ms / 1000)
|
||||
# Never pad past the original length — for near-max-duration uploads
|
||||
# an unconditional pad would push them over the 30 s ceiling and
|
||||
# trigger a spurious "too long" rejection.
|
||||
headroom = (audio.size - trimmed.size) // 2
|
||||
pad = min(pad_each, max(headroom, 0))
|
||||
if pad > 0:
|
||||
trimmed = np.pad(trimmed, (pad, pad), mode="constant")
|
||||
audio = trimmed
|
||||
|
||||
Reference in New Issue
Block a user