Source code for diffsptk.modules.lsp2lpc

# ------------------------------------------------------------------------ #
# 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 torch import nn
import torch.nn.functional as F

from ..misc.utils import check_size
from ..misc.utils import to_3d
from .pol_root import RootsToPolynomial


[docs] class LineSpectralPairsToLinearPredictiveCoefficients(nn.Module): """See `this page <https://sp-nitech.github.io/sptk/latest/main/lsp2lpc.html>`_ for details. Parameters ---------- lpc_order : int >= 0 Order of LPC, :math:`M`. log_gain : bool If True, assume input gain is in log scale. """ def __init__(self, lpc_order, log_gain=False): super().__init__() assert 0 <= lpc_order self.lpc_order = lpc_order self.log_gain = log_gain kernel_p, kernel_q = self._precompute(self.lpc_order) self.register_buffer("kernel_p", kernel_p) self.register_buffer("kernel_q", kernel_q)
[docs] def forward(self, w): """Convert LSP to LPC. Parameters ---------- w : Tensor [shape=(..., M+1)] LSP frequencies in radians. Returns ------- out : Tensor [shape=(..., M+1)] LPC coefficients. Examples -------- >>> w = diffsptk.ramp(3) >>> lsp2lpc = diffsptk.LineSpectralPairsToLinearPredictiveCoefficients(3) >>> a = lsp2lpc(w) >>> a tensor([ 0.0000, 0.8658, -0.0698, 0.0335]) """ check_size(w.size(-1), self.lpc_order + 1, "dimension of LSP") return self._forward(w, self.log_gain, self.kernel_p, self.kernel_q)
@staticmethod def _forward(w, log_gain, kernel_p, kernel_q): M = w.size(-1) - 1 K, w = torch.split(w, [1, M], dim=-1) if log_gain: K = torch.exp(K) if M == 0: return K z = torch.exp(1j * to_3d(w)) p = z[..., 1::2] q = z[..., 0::2] if M == 1: q = RootsToPolynomial._func(torch.cat([q, q.conj()], dim=-1), real=True) a = 0.5 * q[..., 1:-1] else: p = RootsToPolynomial._func(torch.cat([p, p.conj()], dim=-1), real=True) q = RootsToPolynomial._func(torch.cat([q, q.conj()], dim=-1), real=True) p = F.conv1d(p, kernel_p, padding=1 if M % 2 == 1 else 0) q = F.conv1d(q, kernel_q) a = 0.5 * (p + q) a = a.view_as(w) a = torch.cat((K, a), dim=-1) return a @staticmethod def _func(w, log_gain): kernels = LineSpectralPairsToLinearPredictiveCoefficients._precompute( w.size(-1) - 1, dtype=w.dtype, device=w.device ) return LineSpectralPairsToLinearPredictiveCoefficients._forward( w, log_gain, *kernels ) @staticmethod def _precompute(lpc_order, dtype=None, device=None): if lpc_order % 2 == 0: kernel_p = torch.tensor([-1.0, 1.0], dtype=dtype, device=device) kernel_q = torch.tensor([1.0, 1.0], dtype=dtype, device=device) else: kernel_p = torch.tensor([-1.0, 0.0, 1.0], dtype=dtype, device=device) kernel_q = torch.tensor([0.0, 1.0, 0.0], dtype=dtype, device=device) return kernel_p.view(1, 1, -1), kernel_q.view(1, 1, -1)