Source code for diffsptk.core.mcpf

# ------------------------------------------------------------------------ #
# 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 numpy as np
import torch
import torch.nn as nn

from ..misc.utils import default_dtype
from .b2mc import MLSADigitalFilterCoefficientsToMelCepstrum
from .c2acr import CepstrumToAutocorrelation
from .freqt import FrequencyTransform
from .mc2b import MelCepstrumToMLSADigitalFilterCoefficients


[docs]class MelCepstrumPostfiltering(nn.Module): """See `this page <https://sp-nitech.github.io/sptk/latest/main/mcpf.html>`_ for details. Parameters ---------- cep_order : int >= 0 [scalar] Order of mel-cepstrum, :math:`M`. alpha : float [-1 < alpha < 1] Frequency warping factor, :math:`\\alpha`. beta : float [scalar] Intensity parameter, :math:`\\beta`. impulse_response_length : int >= 1 [scalar] Length of impulse response. onset : int >= 0 [scalar] Onset index. """ def __init__(self, cep_order, alpha, beta, onset=2, impulse_response_length=1024): super(MelCepstrumPostfiltering, self).__init__() assert 0 <= onset self.mc2en = nn.Sequential( FrequencyTransform(cep_order, impulse_response_length - 1, -alpha), CepstrumToAutocorrelation(0, impulse_response_length), ) self.mc2b = MelCepstrumToMLSADigitalFilterCoefficients(cep_order, alpha) self.b2mc = MLSADigitalFilterCoefficientsToMelCepstrum(cep_order, alpha) weight = np.full(cep_order + 1, 1 + beta, dtype=default_dtype()) weight[:onset] = 1 self.register_buffer("weight", torch.from_numpy(weight))
[docs] def forward(self, mc1): """Perform mel-cesptrum postfiltering. Parameters ---------- mc1 : Tensor [shape=(..., M+1)] Mel-cepstral coefficients. Returns ------- mc2 : Tensor [shape=(..., M+1)] Postfiltered mel-cepstral coefficients. Examples -------- >>> X = torch.square(torch.randn(5)) >>> X tensor([0.2725, 2.5650, 0.3552, 0.3757, 0.1904]) >>> mcep = diffsptk.MelCepstralAnalysis(3, 8, 0.1) >>> mcpf = diffsptk.MelCepstrumPostfiltering(3, 0.1, 0.2) >>> mc1 = mcep(X) >>> mc1 tensor([-0.2819, 0.3486, -0.2487, -0.3600]) >>> mc2 = mcpf(mc1) >>> mc2 tensor([-0.3256, 0.3486, -0.2984, -0.4320]) """ e1 = self.mc2en(mc1) mc2 = mc1 * self.weight e2 = self.mc2en(mc2) b2 = self.mc2b(mc2) b2[..., :1] += 0.5 * torch.log(e1 / e2) mc2 = self.b2mc(b2) return mc2