Source code for diffsptk.modules.mpir2c

# ------------------------------------------------------------------------ #
# Copyright 2022 SPTK Working Group                                        #
#                                                                          #
# 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.                                           #
# ------------------------------------------------------------------------ #

import torch

from ..typing import Precomputed
from ..utils.private import check_size, clog, get_values
from .base import BaseFunctionalModule


[docs] class MinimumPhaseImpulseResponseToCepstrum(BaseFunctionalModule): """See `this page <https://sp-nitech.github.io/sptk/latest/main/mpir2c.html>`_ for details. Parameters ---------- ir_length : int >= 1 The length of the impulse response, :math:`N`. cep_order : int >= 0 The order of the cepstrum, :math:`M`. n_fft : int >> N The number of FFT bins used for conversion. The accurate conversion requires the large value. """ def __init__(self, ir_length: int, cep_order: int, n_fft: int = 512) -> None: super().__init__() self.in_dim = ir_length self.values = self._precompute(*get_values(locals()))
[docs] def forward(self, h: torch.Tensor) -> torch.Tensor: """Convert minimum-phase impulse response to cepstrum. Parameters ---------- h : Tensor [shape=(..., N)] The truncated minimum-phase impulse response. Returns ------- out : Tensor [shape=(..., M+1)] The cepstral coefficients. Examples -------- >>> h = diffsptk.ramp(4, 0, -1) >>> mpir2c = diffsptk.MinimumPhaseImpulseResponseToCepstrum(5, 3) >>> c = mpir2c(h) >>> c tensor([1.3863, 0.7500, 0.2188, 0.0156]) """ check_size(h.size(-1), self.in_dim, "impulse response length") return self._forward(h, *self.values)
@staticmethod def _func(h: torch.Tensor, *args, **kwargs) -> torch.Tensor: values = MinimumPhaseImpulseResponseToCepstrum._precompute( h.size(-1), *args, **kwargs ) return MinimumPhaseImpulseResponseToCepstrum._forward(h, *values) @staticmethod def _takes_input_size() -> bool: return True @staticmethod def _check(ir_length: int, cep_order: int, n_fft: int) -> None: if ir_length <= 0: raise ValueError("ir_length must be positive.") if cep_order < 0: raise ValueError("cep_order must be non-negative.") if n_fft < max(cep_order + 1, ir_length): raise ValueError("n_fft must be large value.") @staticmethod def _precompute(ir_length: int, cep_order: int, n_fft: int) -> Precomputed: MinimumPhaseImpulseResponseToCepstrum._check(ir_length, cep_order, n_fft) return (cep_order, n_fft) @staticmethod def _forward(h: torch.Tensor, cep_order: int, n_fft: int) -> torch.Tensor: H = torch.fft.fft(h, n=n_fft) c = torch.fft.ifft(clog(H)).real[..., : cep_order + 1] c[..., 1:] *= 2 return c