fix(audio): share bit-depth-aware segment conversion

This commit is contained in:
Palash Debnath
2026-09-17 15:03:07 +05:30
parent 0be2859f75
commit 7182c8d312
2 changed files with 16 additions and 14 deletions
+2 -13
View File
@@ -65,18 +65,7 @@ def load_audio(audio_path: str, sampling_rate: int):
# libraries are absent. The ``backend="soundfile"`` argument above
# does NOT avoid that — 2.9 accepts and ignores it.
aseg = AudioSegment.from_file(audio_path)
# Scale by the decoded sample width instead of a hardcoded 16-bit
# divisor. pydub reports 8-bit as sample_width 1 and widens 24-bit to
# a full-range int32 (sample_width 4), so /32768 makes 24- and 32-bit
# references 32768x too loud and 8-bit ones 256x too quiet.
audio_data = (
np.array(aseg.get_array_of_samples()).astype(np.float32)
/ aseg.max_possible_amplitude
)
if aseg.channels == 1:
waveform = torch.from_numpy(audio_data).unsqueeze(0)
else:
waveform = torch.from_numpy(audio_data.reshape(-1, aseg.channels).T)
waveform = audiosegment_to_tensor(aseg)
prompt_sampling_rate = aseg.frame_rate
if prompt_sampling_rate != sampling_rate:
@@ -255,7 +244,7 @@ def audiosegment_to_tensor(aseg):
audio_data = np.array(aseg.get_array_of_samples())
# Convert to float32 and normalize to [-1, 1] range
audio_data = audio_data.astype(np.float32) / 32768.0
audio_data = audio_data.astype(np.float32) / aseg.max_possible_amplitude
# Handle channels
if aseg.channels == 1:
+14 -1
View File
@@ -23,7 +23,6 @@ import pytest
import soundfile as sf
import torch
from omnivoice.utils.audio import load_audio
def _write_sine_wav(path, *, seconds: float = 0.5, sample_rate: int = 24000):
@@ -43,6 +42,7 @@ def _torchcodec_missing(*_a, **_kw):
def test_load_audio_falls_back_when_torchcodec_missing(tmp_path, monkeypatch):
"""Without the ImportError catch this raises instead of returning audio."""
from omnivoice.utils.audio import load_audio
import torchaudio
ref = tmp_path / "ref.wav"
@@ -60,6 +60,7 @@ def test_load_audio_falls_back_when_torchcodec_missing(tmp_path, monkeypatch):
def test_load_audio_fallback_resamples_to_target(tmp_path, monkeypatch):
"""The fallback path must still honour the requested sampling rate."""
from omnivoice.utils.audio import load_audio
import torchaudio
ref = tmp_path / "ref_16k.wav"
@@ -90,6 +91,7 @@ def test_load_audio_fallback_amplitude_matches_bit_depth(
without TorchCodec it is the only path, which is what makes it a bug
worth fixing here.
"""
from omnivoice.utils.audio import load_audio
import torchaudio
sample_rate = 24000
@@ -106,3 +108,14 @@ def test_load_audio_fallback_amplitude_matches_bit_depth(
f"{subtype} decoded at the wrong scale: peak "
f"{waveform.abs().max().item():.6f}, expected ~{peak}"
)
@pytest.mark.parametrize("subtype", ["PCM_U8", "PCM_16", "PCM_24", "PCM_32"])
def test_audiosegment_conversion_preserves_amplitude(tmp_path, subtype):
from pydub import AudioSegment
from omnivoice.utils.audio import audiosegment_to_tensor
path = tmp_path / "stereo.wav"
samples = np.tile([0.5, -0.25], (100, 1))
sf.write(path, samples, 24000, subtype=subtype)
converted = audiosegment_to_tensor(AudioSegment.from_file(path)).numpy()
np.testing.assert_allclose(converted, samples.T, atol=0.01)