From 1e3bb365214e4bd591e4a185b828f756d21b8fe7 Mon Sep 17 00:00:00 2001 From: Nick Cao Date: Thu, 16 Apr 2026 21:24:47 -0400 Subject: [PATCH] [Refactor] Remove sox from dependencies (#2745) Signed-off-by: Nick Cao Co-authored-by: Claude --- docker/Dockerfile.ci | 2 +- docker/Dockerfile.cuda | 2 +- docker/Dockerfile.rocm | 2 +- .../installation/gpu/rocm.inc.md | 2 +- .../examples/offline_inference/qwen3_tts.md | 4 ++-- .../offline_inference/qwen3_tts/README.md | 4 ++-- requirements/common.txt | 1 - tests/utils/test_audio.py | 22 ++++++++++++++++-- .../qwen3_tts/tokenizer_25hz/vq/speech_vq.py | 9 ++------ vllm_omni/utils/audio.py | 23 +++++++++++++++++++ 10 files changed, 53 insertions(+), 18 deletions(-) diff --git a/docker/Dockerfile.ci b/docker/Dockerfile.ci index 2a98de1b8..9cbf89d0b 100644 --- a/docker/Dockerfile.ci +++ b/docker/Dockerfile.ci @@ -7,7 +7,7 @@ COPY . . # Install system dependencies RUN apt-get update && \ - apt-get install -y espeak-ng git sox libsox-fmt-all jq && \ + apt-get install -y espeak-ng git jq && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* diff --git a/docker/Dockerfile.cuda b/docker/Dockerfile.cuda index 6ed5b7d27..28e10f4fb 100644 --- a/docker/Dockerfile.cuda +++ b/docker/Dockerfile.cuda @@ -7,7 +7,7 @@ WORKDIR ${COMMON_WORKDIR} # Step 1: Setup - Install system dependencies RUN apt-get update && \ - apt-get install -y git sox libsox-fmt-all jq && \ + apt-get install -y git jq && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* diff --git a/docker/Dockerfile.rocm b/docker/Dockerfile.rocm index b34478389..a54aa3b79 100644 --- a/docker/Dockerfile.rocm +++ b/docker/Dockerfile.rocm @@ -21,7 +21,7 @@ WORKDIR ${COMMON_WORKDIR} # Need to include ffmpeg because vllm rocm upstream docker image # does not include it. RUN apt-get update && \ - apt-get install -y espeak-ng ffmpeg git sox libsox-fmt-all jq && \ + apt-get install -y espeak-ng ffmpeg git jq && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* diff --git a/docs/getting_started/installation/gpu/rocm.inc.md b/docs/getting_started/installation/gpu/rocm.inc.md index 1a683d174..5dfea8d2f 100644 --- a/docs/getting_started/installation/gpu/rocm.inc.md +++ b/docs/getting_started/installation/gpu/rocm.inc.md @@ -26,7 +26,7 @@ uv pip install vllm-omni # Optional if want to run Qwen3 TTS uv pip uninstall onnxruntime # should be removed before we can install onnxruntime-rocm -uv pip install onnxruntime-rocm sox +uv pip install onnxruntime-rocm ``` # --8<-- [end:pre-built-wheels] diff --git a/docs/user_guide/examples/offline_inference/qwen3_tts.md b/docs/user_guide/examples/offline_inference/qwen3_tts.md index 19fea4132..4ece5219d 100644 --- a/docs/user_guide/examples/offline_inference/qwen3_tts.md +++ b/docs/user_guide/examples/offline_inference/qwen3_tts.md @@ -18,11 +18,11 @@ Please refer to the [stage configuration documentation](https://docs.vllm.ai/pro ### ROCm Dependencies -You will need to install these two dependencies `onnxruntime-rocm` and `sox`. +You will need to install the dependency `onnxruntime-rocm`. ``` pip uninstall onnxruntime # should be removed before we can install onnxruntime-rocm -pip install onnxruntime-rocm sox +pip install onnxruntime-rocm ``` ## Quick Start diff --git a/examples/offline_inference/qwen3_tts/README.md b/examples/offline_inference/qwen3_tts/README.md index bf59dc9ba..c38a2b462 100644 --- a/examples/offline_inference/qwen3_tts/README.md +++ b/examples/offline_inference/qwen3_tts/README.md @@ -15,11 +15,11 @@ Please refer to the [stage configuration documentation](https://docs.vllm.ai/pro ### ROCm Dependencies -You will need to install these two dependencies `onnxruntime-rocm` and `sox`. +You will need to install the dependency `onnxruntime-rocm`. ``` pip uninstall onnxruntime # should be removed before we can install onnxruntime-rocm -pip install onnxruntime-rocm sox +pip install onnxruntime-rocm ``` ## Quick Start diff --git a/requirements/common.txt b/requirements/common.txt index 1fff58444..1f44d343c 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -10,7 +10,6 @@ tqdm>=4.66.0 torchsde>=0.2.6 openai-whisper>=20250625 imageio[ffmpeg]>=2.37.2 -sox>=1.5.0 x-transformers>=2.12.2 einops>=0.8.1 prettytable>=3.8.0 diff --git a/tests/utils/test_audio.py b/tests/utils/test_audio.py index cfbd2501b..0e483e646 100644 --- a/tests/utils/test_audio.py +++ b/tests/utils/test_audio.py @@ -1,12 +1,13 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project -"""Unit tests for vllm_omni.utils.audio.mel_filter_bank.""" +"""Unit tests for vllm_omni.utils.audio.""" +import numpy as np import pytest import torch -from vllm_omni.utils.audio import mel_filter_bank +from vllm_omni.utils.audio import mel_filter_bank, peak_normalize # Parameter combinations used across the codebase. _PARAM_SETS = [ @@ -59,3 +60,20 @@ class TestMelFilterBank: last_nonzero_low = (fb_low.sum(dim=0) > 0).nonzero()[-1].item() last_nonzero_high = (fb_high.sum(dim=0) > 0).nonzero()[-1].item() assert last_nonzero_high > last_nonzero_low + + +class TestPeakNormalize: + def test_silence_unchanged(self): + """All-zero input should remain all-zero.""" + audio = np.zeros(1600, dtype=np.float32) + result = peak_normalize(audio, db_level=-6.0) + np.testing.assert_array_equal(result, audio) + + def test_peak_reaches_target(self): + """After normalization, peak amplitude should be at target dB.""" + rng = np.random.default_rng(7) + audio = rng.uniform(-0.4, 0.4, size=16000).astype(np.float32) + + result = peak_normalize(audio, db_level=-6.0) + peak_db = 20 * np.log10(np.abs(result).max()) + np.testing.assert_allclose(peak_db, -6.0, atol=1e-4) diff --git a/vllm_omni/model_executor/models/qwen3_tts/tokenizer_25hz/vq/speech_vq.py b/vllm_omni/model_executor/models/qwen3_tts/tokenizer_25hz/vq/speech_vq.py index 9bb2f78c5..92cecbff1 100644 --- a/vllm_omni/model_executor/models/qwen3_tts/tokenizer_25hz/vq/speech_vq.py +++ b/vllm_omni/model_executor/models/qwen3_tts/tokenizer_25hz/vq/speech_vq.py @@ -17,14 +17,13 @@ import operator from itertools import accumulate import onnxruntime -import sox import torch import torch.nn as nn import torch.nn.functional as F import torchaudio.compliance.kaldi as kaldi from torch import Tensor -from vllm_omni.utils.audio import mel_filter_bank +from vllm_omni.utils.audio import mel_filter_bank, peak_normalize from .core_vq import DistributedGroupResidualVectorQuantization from .whisper_encoder import Conv1d, ConvTranspose1d, WhisperEncoder @@ -153,9 +152,6 @@ class XVectorExtractor(nn.Module): audio_codec_with_xvector, sess_options=option, providers=providers ) - self.tfm = sox.Transformer() - self.tfm.norm(db_level=-6) - self.mel_ext = MelSpectrogramFeatures( filter_length=1024, hop_length=160, @@ -183,8 +179,7 @@ class XVectorExtractor(nn.Module): return norm_embedding.numpy(), ref_mel.permute(0, 2, 1).squeeze(0).numpy() def sox_norm(self, audio): - wav_norm = self.tfm.build_array(input_array=audio, sample_rate_in=16000) - return wav_norm + return peak_normalize(audio, db_level=-6) class WhisperEncoderVQ(WhisperEncoder): diff --git a/vllm_omni/utils/audio.py b/vllm_omni/utils/audio.py index 490737bd5..cc25c1794 100644 --- a/vllm_omni/utils/audio.py +++ b/vllm_omni/utils/audio.py @@ -3,6 +3,7 @@ """Audio utility functions shared across models and entrypoints.""" +import numpy as np import torch from torchaudio.functional import melscale_fbanks @@ -43,3 +44,25 @@ def mel_filter_bank( mel_scale="slaney", norm="slaney", ).T + + +def peak_normalize( + audio: np.ndarray, + db_level: float = -6.0, +) -> np.ndarray: + """Normalize audio so peak amplitude reaches a target dB level. + + Drop-in replacement for ``sox.Transformer().norm(db_level=...)``. + + Args: + audio: Input waveform as a 1-D numpy array. + db_level: Target peak amplitude in dBFS. + + Returns: + Normalized waveform with the same dtype as *audio*. + """ + peak = np.abs(audio).max() + if peak == 0: + return audio + target = 10.0 ** (db_level / 20.0) + return audio * (target / peak)