612 lines
21 KiB
Python
612 lines
21 KiB
Python
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
# Modified from librosa(https://github.com/librosa/librosa)
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
from typing import TYPE_CHECKING, Literal, TypeVar
|
|
|
|
import paddle
|
|
from paddle import Tensor
|
|
from paddle.base.framework import Variable
|
|
from paddle.pir import Value
|
|
|
|
if TYPE_CHECKING:
|
|
_TensorOrFloat = TypeVar("_TensorOrFloat", Tensor, float)
|
|
|
|
|
|
def hz_to_mel(freq: _TensorOrFloat, htk: bool = False) -> _TensorOrFloat:
|
|
"""Convert Hz to Mels.
|
|
|
|
Args:
|
|
freq (Union[Tensor, float]): The input tensor with arbitrary shape.
|
|
htk (bool, optional): Use htk scaling. Defaults to False.
|
|
|
|
Returns:
|
|
Union[Tensor, float]: Frequency in mels.
|
|
|
|
Examples:
|
|
.. code-block:: pycon
|
|
|
|
>>> import paddle
|
|
|
|
>>> val = 3.0
|
|
>>> htk_flag = True
|
|
>>> mel_paddle_tensor = paddle.audio.functional.hz_to_mel(paddle.to_tensor(val), htk_flag)
|
|
"""
|
|
|
|
if htk:
|
|
if isinstance(freq, (Tensor, Variable, Value)):
|
|
return 2595.0 * paddle.log10(1.0 + freq / 700.0)
|
|
else:
|
|
return 2595.0 * math.log10(1.0 + freq / 700.0)
|
|
|
|
# Fill in the linear part
|
|
f_min = 0.0
|
|
f_sp = 200.0 / 3
|
|
|
|
mels = (freq - f_min) / f_sp
|
|
|
|
# Fill in the log-scale part
|
|
|
|
min_log_hz = 1000.0 # beginning of log region (Hz)
|
|
min_log_mel = (min_log_hz - f_min) / f_sp # same (Mels)
|
|
logstep = math.log(6.4) / 27.0 # step size for log region
|
|
|
|
if isinstance(freq, (Tensor, Variable, Value)):
|
|
target = (
|
|
min_log_mel + paddle.log(freq / min_log_hz + 1e-10) / logstep
|
|
) # prevent nan with 1e-10
|
|
mask = (freq > min_log_hz).astype(freq.dtype)
|
|
mels = target * mask + mels * (
|
|
1 - mask
|
|
) # will replace by masked_fill OP in future
|
|
else:
|
|
if freq >= min_log_hz:
|
|
mels = min_log_mel + math.log(freq / min_log_hz + 1e-10) / logstep
|
|
|
|
return mels
|
|
|
|
|
|
def mel_to_hz(mel: _TensorOrFloat, htk: bool = False) -> _TensorOrFloat:
|
|
"""Convert mel bin numbers to frequencies.
|
|
|
|
Args:
|
|
mel (Union[float, Tensor]): The mel frequency represented as a tensor with arbitrary shape.
|
|
htk (bool, optional): Use htk scaling. Defaults to False.
|
|
|
|
Returns:
|
|
Union[float, Tensor]: Frequencies in Hz.
|
|
|
|
Examples:
|
|
.. code-block:: pycon
|
|
|
|
>>> import paddle
|
|
|
|
>>> val = 3.0
|
|
>>> htk_flag = True
|
|
>>> mel_paddle_tensor = paddle.audio.functional.mel_to_hz(paddle.to_tensor(val), htk_flag)
|
|
"""
|
|
if htk:
|
|
return 700.0 * (10.0 ** (mel / 2595.0) - 1.0)
|
|
|
|
f_min = 0.0
|
|
f_sp = 200.0 / 3
|
|
freqs = f_min + f_sp * mel
|
|
# And now the nonlinear scale
|
|
min_log_hz = 1000.0 # beginning of log region (Hz)
|
|
min_log_mel = (min_log_hz - f_min) / f_sp # same (Mels)
|
|
logstep = math.log(6.4) / 27.0 # step size for log region
|
|
if isinstance(mel, (Tensor, Variable, Value)):
|
|
target = min_log_hz * paddle.exp(logstep * (mel - min_log_mel))
|
|
mask = (mel > min_log_mel).astype(mel.dtype)
|
|
freqs = target * mask + freqs * (
|
|
1 - mask
|
|
) # will replace by masked_fill OP in future
|
|
else:
|
|
if mel >= min_log_mel:
|
|
freqs = min_log_hz * math.exp(logstep * (mel - min_log_mel))
|
|
return freqs
|
|
|
|
|
|
def mel_frequencies(
|
|
n_mels: int = 64,
|
|
f_min: float = 0.0,
|
|
f_max: float = 11025.0,
|
|
htk: bool = False,
|
|
dtype: str = 'float32',
|
|
) -> Tensor:
|
|
"""Compute mel frequencies.
|
|
|
|
Args:
|
|
n_mels (int, optional): Number of mel bins. Defaults to 64.
|
|
f_min (float, optional): Minimum frequency in Hz. Defaults to 0.0.
|
|
fmax (float, optional): Maximum frequency in Hz. Defaults to 11025.0.
|
|
htk (bool, optional): Use htk scaling. Defaults to False.
|
|
dtype (str, optional): The data type of the return frequencies. Defaults to 'float32'.
|
|
|
|
Returns:
|
|
Tensor: Tensor of n_mels frequencies in Hz with shape `(n_mels,)`.
|
|
|
|
Examples:
|
|
.. code-block:: pycon
|
|
|
|
>>> import paddle
|
|
|
|
>>> n_mels = 64
|
|
>>> f_min = 0.5
|
|
>>> f_max = 10000
|
|
>>> htk_flag = True
|
|
|
|
>>> paddle_mel_freq = paddle.audio.functional.mel_frequencies(n_mels, f_min, f_max, htk_flag, 'float64')
|
|
"""
|
|
# 'Center freqs' of mel bands - uniformly spaced between limits
|
|
min_mel = hz_to_mel(f_min, htk=htk)
|
|
max_mel = hz_to_mel(f_max, htk=htk)
|
|
mels = paddle.linspace(min_mel, max_mel, n_mels, dtype=dtype)
|
|
freqs = mel_to_hz(mels, htk=htk)
|
|
return freqs
|
|
|
|
|
|
def fft_frequencies(sr: int, n_fft: int, dtype: str = 'float32') -> Tensor:
|
|
"""Compute fourier frequencies.
|
|
|
|
Args:
|
|
sr (int): Sample rate.
|
|
n_fft (int): Number of fft bins.
|
|
dtype (str, optional): The data type of the return frequencies. Defaults to 'float32'.
|
|
|
|
Returns:
|
|
Tensor: FFT frequencies in Hz with shape `(n_fft//2 + 1,)`.
|
|
|
|
Examples:
|
|
.. code-block:: pycon
|
|
|
|
>>> import paddle
|
|
|
|
>>> sr = 16000
|
|
>>> n_fft = 128
|
|
>>> fft_freq = paddle.audio.functional.fft_frequencies(sr, n_fft)
|
|
"""
|
|
return paddle.linspace(0, float(sr) / 2, int(1 + n_fft // 2), dtype=dtype)
|
|
|
|
|
|
def compute_fbank_matrix(
|
|
sr: int,
|
|
n_fft: int,
|
|
n_mels: int = 64,
|
|
f_min: float = 0.0,
|
|
f_max: float | None = None,
|
|
htk: bool = False,
|
|
norm: Literal['slaney'] | float = 'slaney',
|
|
dtype: str = 'float32',
|
|
) -> Tensor:
|
|
"""Compute fbank matrix.
|
|
|
|
Args:
|
|
sr (int): Sample rate.
|
|
n_fft (int): Number of fft bins.
|
|
n_mels (int, optional): Number of mel bins. Defaults to 64.
|
|
f_min (float, optional): Minimum frequency in Hz. Defaults to 0.0.
|
|
f_max (Optional[float], optional): Maximum frequency in Hz. Defaults to None.
|
|
htk (bool, optional): Use htk scaling. Defaults to False.
|
|
norm (Union[str, float], optional): Type of normalization. Defaults to 'slaney'.
|
|
dtype (str, optional): The data type of the return matrix. Defaults to 'float32'.
|
|
|
|
Returns:
|
|
Tensor: Mel transform matrix with shape `(n_mels, n_fft//2 + 1)`.
|
|
|
|
Examples:
|
|
.. code-block:: pycon
|
|
|
|
>>> import paddle
|
|
|
|
>>> sr = 23
|
|
>>> n_fft = 51
|
|
>>> fbank = paddle.audio.functional.compute_fbank_matrix(sr, n_fft)
|
|
"""
|
|
|
|
if f_max is None:
|
|
f_max = float(sr) / 2
|
|
|
|
# Initialize the weights
|
|
weights = paddle.zeros((n_mels, int(1 + n_fft // 2)), dtype=dtype)
|
|
|
|
# Center freqs of each FFT bin
|
|
fftfreqs = fft_frequencies(sr=sr, n_fft=n_fft, dtype=dtype)
|
|
|
|
# 'Center freqs' of mel bands - uniformly spaced between limits
|
|
mel_f = mel_frequencies(
|
|
n_mels + 2, f_min=f_min, f_max=f_max, htk=htk, dtype=dtype
|
|
)
|
|
|
|
fdiff = mel_f[1:] - mel_f[:-1] # np.diff(mel_f)
|
|
ramps = mel_f.unsqueeze(1) - fftfreqs.unsqueeze(0)
|
|
# ramps = np.subtract.outer(mel_f, fftfreqs)
|
|
|
|
for i in range(n_mels):
|
|
# lower and upper slopes for all bins
|
|
lower = -ramps[i] / fdiff[i]
|
|
upper = ramps[i + 2] / fdiff[i + 1]
|
|
|
|
# .. then intersect them with each other and zero
|
|
weights[i] = paddle.maximum(
|
|
paddle.zeros_like(lower), paddle.minimum(lower, upper)
|
|
)
|
|
|
|
# Slaney-style mel is scaled to be approx constant energy per channel
|
|
if norm == 'slaney':
|
|
enorm = 2.0 / (mel_f[2 : n_mels + 2] - mel_f[:n_mels])
|
|
weights *= enorm.unsqueeze(1)
|
|
elif isinstance(norm, (int, float)):
|
|
weights = paddle.nn.functional.normalize(weights, p=norm, axis=-1)
|
|
|
|
return weights
|
|
|
|
|
|
def power_to_db(
|
|
spect: Tensor,
|
|
ref_value: float = 1.0,
|
|
amin: float = 1e-10,
|
|
top_db: float | None = 80.0,
|
|
) -> Tensor:
|
|
"""Convert a power spectrogram (amplitude squared) to decibel (dB) units. The function computes the scaling `10 * log10(x / ref)` in a numerically stable way.
|
|
|
|
Args:
|
|
spect (Tensor): STFT power spectrogram.
|
|
ref_value (float, optional): The reference value. If smaller than 1.0, the db level of the signal will be pulled up accordingly. Otherwise, the db level is pushed down. Defaults to 1.0.
|
|
amin (float, optional): Minimum threshold. Defaults to 1e-10.
|
|
top_db (Optional[float], optional): Threshold the output at `top_db` below the peak. Defaults to None.
|
|
|
|
Returns:
|
|
Tensor: Power spectrogram in db scale.
|
|
|
|
Examples:
|
|
.. code-block:: pycon
|
|
|
|
>>> import paddle
|
|
|
|
>>> val = 3.0
|
|
>>> decibel_paddle = paddle.audio.functional.power_to_db(paddle.to_tensor(val))
|
|
"""
|
|
if amin <= 0:
|
|
raise Exception("amin must be strictly positive")
|
|
|
|
if ref_value <= 0:
|
|
raise Exception("ref_value must be strictly positive")
|
|
|
|
ones = paddle.ones_like(spect)
|
|
log_spec = 10.0 * paddle.log10(paddle.maximum(ones * amin, spect))
|
|
log_spec -= 10.0 * math.log10(max(ref_value, amin))
|
|
|
|
if top_db is not None:
|
|
if top_db < 0:
|
|
raise Exception("top_db must be non-negative")
|
|
log_spec = paddle.maximum(log_spec, ones * (log_spec.max() - top_db))
|
|
|
|
return log_spec
|
|
|
|
|
|
def create_dct(
|
|
n_mfcc: int,
|
|
n_mels: int,
|
|
norm: Literal['ortho'] | None = 'ortho',
|
|
dtype: str = 'float32',
|
|
) -> Tensor:
|
|
"""Create a discrete cosine transform(DCT) matrix.
|
|
|
|
Args:
|
|
n_mfcc (int): Number of mel frequency cepstral coefficients.
|
|
n_mels (int): Number of mel filterbanks.
|
|
norm (Optional[str], optional): Normalization type. Defaults to 'ortho'.
|
|
dtype (str, optional): The data type of the return matrix. Defaults to 'float32'.
|
|
|
|
Returns:
|
|
Tensor: The DCT matrix with shape `(n_mels, n_mfcc)`.
|
|
|
|
Examples:
|
|
.. code-block:: pycon
|
|
|
|
>>> import paddle
|
|
>>> n_mfcc = 23
|
|
>>> n_mels = 257
|
|
>>> dct = paddle.audio.functional.create_dct(n_mfcc, n_mels)
|
|
"""
|
|
n = paddle.arange(n_mels, dtype=dtype)
|
|
k = paddle.arange(n_mfcc, dtype=dtype).unsqueeze(1)
|
|
dct = paddle.cos(
|
|
math.pi / float(n_mels) * (n + 0.5) * k
|
|
) # size (n_mfcc, n_mels)
|
|
if norm is None:
|
|
dct *= 2.0
|
|
else:
|
|
assert norm == "ortho"
|
|
dct[0] *= 1.0 / math.sqrt(2.0)
|
|
dct *= math.sqrt(2.0 / float(n_mels))
|
|
return dct.T
|
|
|
|
|
|
def _get_sinc_resample_kernel(
|
|
orig_freq: int,
|
|
new_freq: int,
|
|
gcd: int,
|
|
lowpass_filter_width: int = 6,
|
|
rolloff: float = 0.99,
|
|
resampling_method: Literal[
|
|
"sinc_interp_hann", "sinc_interp_kaiser"
|
|
] = "sinc_interp_hann",
|
|
beta: float | None = None,
|
|
dtype: paddle.dtype | None = None,
|
|
):
|
|
"""
|
|
Generate the sinc interpolation kernel for resampling.
|
|
|
|
This internal function computes the resampling kernel based on the sinc
|
|
interpolation formula with windowing. The kernel is used by
|
|
_apply_sinc_resample_kernel to perform the actual resampling.
|
|
|
|
Args:
|
|
orig_freq (int): Original sampling frequency.
|
|
new_freq (int): Target sampling frequency.
|
|
gcd (int): Greatest common divisor of orig_freq and new_freq.
|
|
lowpass_filter_width (int, optional): Controls the sharpness of the filter,
|
|
larger value means sharper but less efficient. Default: 6.
|
|
rolloff (float, optional): Roll-off frequency as a fraction of the Nyquist.
|
|
Lower values reduce anti-aliasing but also attenuate high frequencies.
|
|
Default: 0.99.
|
|
resampling_method (str, optional): Window method for filter design.
|
|
Options: ["sinc_interp_hann", "sinc_interp_kaiser"]. Default: "sinc_interp_hann".
|
|
beta (float, optional): Shape parameter for Kaiser window. Required only
|
|
when resampling_method="sinc_interp_kaiser". Default: None.
|
|
dtype (paddle.dtype, optional): Data type for kernel computation.
|
|
If None, uses float64 for computation and converts to float32 for output.
|
|
Default: None.
|
|
|
|
Returns:
|
|
tuple: (kernel, width)
|
|
- kernel (Tensor): Resampling kernel of shape (1, 1, kernel_width)
|
|
- width (int): Half-width of the filter in terms of input samples
|
|
|
|
Raises:
|
|
Exception: If frequencies are not integers.
|
|
ValueError: If resampling_method is invalid or lowpass_filter_width <= 0.
|
|
"""
|
|
if not (int(orig_freq) == orig_freq and int(new_freq) == new_freq):
|
|
raise ValueError(
|
|
"Frequencies must be of integer type to ensure quality resampling computation. "
|
|
"To work around this, manually convert both frequencies to integer values "
|
|
"that maintain their resampling rate ratio before passing them into the function. "
|
|
"Example: To downsample a 44100 hz waveform by a factor of 8, use "
|
|
"`orig_freq=8` and `new_freq=1` instead of `orig_freq=44100` and `new_freq=5512.5`. "
|
|
)
|
|
|
|
if resampling_method not in ["sinc_interp_hann", "sinc_interp_kaiser"]:
|
|
raise ValueError(f"Invalid resampling method: {resampling_method}")
|
|
|
|
orig_freq = int(orig_freq) // gcd
|
|
new_freq = int(new_freq) // gcd
|
|
|
|
if lowpass_filter_width <= 0:
|
|
raise ValueError("Low pass filter width should be positive.")
|
|
base_freq = min(orig_freq, new_freq)
|
|
|
|
# Perform antialiasing filtering by removing the highest frequencies.
|
|
base_freq *= rolloff
|
|
|
|
# Calculate filter width based on lowpass_filter_width and frequency ratio
|
|
width = math.ceil(lowpass_filter_width * orig_freq / base_freq)
|
|
idx_dtype = dtype if dtype is not None else paddle.float64
|
|
|
|
idx = (
|
|
paddle.arange(-width, width + orig_freq, dtype=idx_dtype)[None, None]
|
|
/ orig_freq
|
|
)
|
|
|
|
t = (
|
|
paddle.arange(0, -new_freq, -1, dtype=dtype)[:, None, None] / new_freq
|
|
+ idx
|
|
)
|
|
t *= base_freq
|
|
t = t.clip_(-lowpass_filter_width, lowpass_filter_width)
|
|
|
|
# we do not use built-in paddle windows here as we need to evaluate the window
|
|
# at specific positions, not over a regular grid.
|
|
if resampling_method == "sinc_interp_hann":
|
|
window = paddle.cos(t * math.pi / lowpass_filter_width / 2) ** 2
|
|
else:
|
|
# sinc_interp_kaiser
|
|
if beta is None:
|
|
beta = 14.769656459379492
|
|
beta_tensor = paddle.to_tensor(float(beta))
|
|
window = paddle.i0(
|
|
beta_tensor * paddle.sqrt(1 - (t / lowpass_filter_width) ** 2),
|
|
) / paddle.i0(beta_tensor)
|
|
|
|
t *= math.pi
|
|
|
|
scale = base_freq / orig_freq
|
|
kernels = paddle.where(
|
|
t == 0, paddle.to_tensor(1.0).cast(t.dtype), t.sin() / t
|
|
)
|
|
kernels *= window * scale
|
|
|
|
if dtype is None: # pragma: no cover
|
|
kernels = kernels.cast(paddle.float32)
|
|
|
|
return kernels, width
|
|
|
|
|
|
def _apply_sinc_resample_kernel(
|
|
waveform: Tensor,
|
|
orig_freq: int,
|
|
new_freq: int,
|
|
gcd: int,
|
|
kernel: Tensor,
|
|
width: int,
|
|
):
|
|
"""
|
|
Apply sinc interpolation resampling using precomputed kernel.
|
|
|
|
This internal function performs the actual resampling operation using the
|
|
kernel generated by _get_sinc_resample_kernel. It handles batch processing
|
|
and ensures correct output length.
|
|
|
|
Args:
|
|
waveform (Tensor): Input waveform of shape (..., time). Must be floating point.
|
|
orig_freq (int): Original sampling frequency.
|
|
new_freq (int): Target sampling frequency.
|
|
gcd (int): Greatest common divisor of orig_freq and new_freq.
|
|
kernel (Tensor): Resampling kernel from _get_sinc_resample_kernel.
|
|
width (int): Half-width of the filter from _get_sinc_resample_kernel.
|
|
|
|
Returns:
|
|
Tensor: Resampled waveform of shape (..., new_time).
|
|
|
|
"""
|
|
|
|
orig_freq = int(orig_freq) // gcd
|
|
new_freq = int(new_freq) // gcd
|
|
|
|
# pack batch
|
|
shape = waveform.shape
|
|
waveform = waveform.reshape([-1, shape[-1]])
|
|
|
|
num_wavs, length = waveform.shape
|
|
waveform = paddle.nn.functional.pad(waveform, (width, width + orig_freq))
|
|
resampled = paddle.nn.functional.conv1d(
|
|
waveform[:, None], kernel, stride=orig_freq
|
|
)
|
|
resampled = resampled.transpose([0, 2, 1]).reshape((num_wavs, -1))
|
|
target_length = paddle.ceil(
|
|
paddle.to_tensor(new_freq * length / orig_freq)
|
|
).astype(paddle.int64)
|
|
resampled = resampled[..., :target_length]
|
|
|
|
# unpack batch
|
|
resampled = resampled.reshape(shape[:-1] + resampled.shape[-1:])
|
|
return resampled
|
|
|
|
|
|
def resample(
|
|
waveform: Tensor,
|
|
orig_freq: int,
|
|
new_freq: int,
|
|
lowpass_filter_width: int = 6,
|
|
rolloff: float = 0.99,
|
|
resampling_method: Literal[
|
|
"sinc_interp_hann", "sinc_interp_kaiser"
|
|
] = "sinc_interp_hann",
|
|
beta: float | None = None,
|
|
) -> Tensor:
|
|
"""
|
|
Resample the waveform from orig_freq to new_freq using bandlimited interpolation.
|
|
|
|
This function implements resampling through sinc interpolation with windowing.
|
|
It first computes a resampling kernel based on the specified parameters, then
|
|
applies it to the input waveform using convolution. The algorithm handles both
|
|
upsampling and downsampling while minimizing aliasing artifacts.
|
|
|
|
Args:
|
|
waveform (Tensor): The input signal of dimension (..., time). Must be
|
|
floating point type (float32 or float64).
|
|
orig_freq (int): The original frequency of the signal. Must be positive.
|
|
new_freq (int): The desired target frequency. Must be positive.
|
|
lowpass_filter_width (int, optional): Controls the sharpness of the filter.
|
|
Larger values give sharper filtering but are less efficient.
|
|
Default: 6.
|
|
rolloff (float, optional): The roll-off frequency of the filter as a fraction
|
|
of the Nyquist frequency. Lower values reduce anti-aliasing but also
|
|
attenuate some high frequencies. Default: 0.99.
|
|
resampling_method (str, optional): The windowing method to use for filter
|
|
design. Options: "sinc_interp_hann" (Hann window) or "sinc_interp_kaiser"
|
|
(Kaiser window). Default: "sinc_interp_hann".
|
|
beta (float, optional): Shape parameter for the Kaiser window. Required only
|
|
when resampling_method="sinc_interp_kaiser". If not provided for Kaiser,
|
|
a default value of 14.769656459379492 is used. Default: None.
|
|
|
|
Returns:
|
|
Tensor: The waveform resampled to new_freq, with dimension (..., new_time).
|
|
|
|
Raises:
|
|
ValueError: If orig_freq or new_freq are not positive.
|
|
Exception: If frequencies are not integers (see note below).
|
|
TypeError: If waveform is not floating point.
|
|
|
|
Note:
|
|
- orig_freq and new_freq must be integers. For non-integer frequencies,
|
|
convert them to integers while maintaining the ratio.
|
|
- For repeated resampling with same parameters, use
|
|
:class:`paddle.audio.transforms.Resample` for better efficiency.
|
|
- Uses windowed sinc interpolation for high-quality audio resampling.
|
|
- This function does not support ONNX export now.
|
|
|
|
Examples:
|
|
.. code-block:: pycon
|
|
|
|
>>> import paddle
|
|
>>> from paddle.audio.functional import resample
|
|
|
|
>>> # Create a sample waveform (1 channel, 1000 samples at 16000 Hz)
|
|
>>> waveform = paddle.randn([1, 1000])
|
|
|
|
>>> # Downsample from 16000 Hz to 8000 Hz
|
|
>>> resampled = resample(waveform, 16000, 8000)
|
|
>>> print(resampled.shape)
|
|
paddle.Size([1, 500])
|
|
|
|
>>> # Upsample from 16000 Hz to 48000 Hz with custom filter width
|
|
>>> resampled = resample(waveform, 16000, 48000, lowpass_filter_width=12)
|
|
>>> print(resampled.shape)
|
|
paddle.Size([1, 3000])
|
|
|
|
>>> # Use Kaiser window resampling
|
|
>>> resampled = resample(waveform, 16000, 8000, resampling_method="sinc_interp_kaiser", beta=12.0)
|
|
>>> print(resampled.shape)
|
|
paddle.Size([1, 500])
|
|
|
|
>>> # Batch processing: multiple waveforms
|
|
>>> batch_waveforms = paddle.randn([4, 1, 1000]) # [batch, channels, time]
|
|
>>> resampled_batch = resample(batch_waveforms, 16000, 8000)
|
|
>>> print(resampled_batch.shape)
|
|
paddle.Size([4, 1, 500])
|
|
"""
|
|
if orig_freq <= 0.0 or new_freq <= 0.0:
|
|
raise ValueError(
|
|
"Original frequency and desired frequency should be positive integers"
|
|
)
|
|
if not waveform.is_floating_point():
|
|
raise TypeError(
|
|
f"Expected floating point type for waveform tensor, but received {waveform.dtype}."
|
|
)
|
|
|
|
if orig_freq == new_freq:
|
|
return waveform
|
|
|
|
gcd = math.gcd(int(orig_freq), int(new_freq))
|
|
|
|
kernel, width = _get_sinc_resample_kernel(
|
|
orig_freq,
|
|
new_freq,
|
|
gcd,
|
|
lowpass_filter_width,
|
|
rolloff,
|
|
resampling_method,
|
|
beta,
|
|
waveform.dtype,
|
|
)
|
|
resampled = _apply_sinc_resample_kernel(
|
|
waveform, orig_freq, new_freq, gcd, kernel, width
|
|
)
|
|
return resampled
|