Source code for diffsptk.core.freqt2
# ------------------------------------------------------------------------ #
# 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 numpy_to_torch
def warp(omega, alpha, theta):
"""Warp frequency.
Parameters
----------
omega : float [0 <= omega <= 2pi]
Frequency.
alpha : float [-1 < alpha < 1]
Frequency warping factor, :math:`\\alpha`.
theta : float [0 <= theta <= 1]
Emphasis frequency, :math:`\\theta`.
Returns
-------
w : float
Warped frequency.
"""
x = omega - theta
y = omega + theta
w = (
omega
+ np.arctan2(alpha * np.sin(x), 1 - alpha * np.cos(x))
+ np.arctan2(alpha * np.sin(y), 1 - alpha * np.cos(y))
)
return w
[docs]class SecondOrderAllPassFrequencyTransform(nn.Module):
"""Second-order all-pass frequecy transform module.
Parameters
----------
in_order : int >= 0 [scalar]
Order of input sequence, :math:`M_1`.
out_order : int >= 0 [scalar]
Order of output sequence, :math:`M_2`.
alpha : float [-1 < alpha < 1]
Frequency warping factor, :math:`\\alpha`.
theta : float [0 <= theta <= 1]
Emphasis frequency, :math:`\\theta`.
n_fft : int >> :math:`M_2` [scalar]
Number of FFT bins. Accurate conversion requires the large value.
"""
def __init__(self, in_order, out_order, alpha=0, theta=0, n_fft=512):
super(SecondOrderAllPassFrequencyTransform, self).__init__()
assert 0 <= in_order
assert 0 <= out_order
assert out_order < n_fft
assert abs(alpha) < 1
assert 0 <= theta <= 1
def diff_warp(omega, alpha, theta):
x = omega - theta
y = omega + theta
a1 = alpha
a2 = alpha + alpha
aa = alpha * alpha
return (
1
+ (a1 * np.cos(x) - aa) / (1 - a2 * np.cos(x) + aa)
+ (a1 * np.cos(y) - aa) / (1 - a2 * np.cos(y) + aa)
)
theta *= np.pi
delta = 2 * np.pi / n_fft
omega = np.arange(n_fft) * delta
ww = warp(omega, alpha, theta)
dw = diff_warp(omega, alpha, theta)
m2 = np.arange(out_order + 1)
wwm2 = ww.reshape(-1, 1) * m2.reshape(1, -1)
real = np.cos(wwm2) * dw.reshape(-1, 1)
imag = -np.sin(wwm2) * dw.reshape(-1, 1)
M1 = in_order + 1
A = np.fft.ifft(real + 1j * imag, axis=0).real
if 2 <= M1:
A[1:M1] += np.flip(A[-(M1 - 1) :], axis=0)
A = A[:M1]
A[1:, 0] /= 2
A[0, 1:] *= 2
self.register_buffer("A", numpy_to_torch(A))
[docs] def forward(self, c1):
"""Perform second-order all-pass frequency transform.
Parameters
----------
c1 : Tensor [shape=(..., M1+1)]
Input sequence.
Returns
-------
c2 : Tensor [shape=(..., M2+1)]
Warped sequence.
Examples
--------
>>> c1 = diffsptk.nrand(3)
>>> c1
tensor([ 0.0304, 0.5849, -0.8668, -0.7278])
>>> freqt2 = diffsptk.SecondOrderAllPassFrequencyTransform(3, 4, .1, .3)
>>> c2 = freqt2(c1)
>>> c2
tensor([ 0.0682, 0.4790, -1.0168, -0.6026, 0.1094])
>>> ifreqt2 = diffsptk.SecondOrderAllPassInverseFrequencyTransform(4, 3, .1, .3)
>>> c3 = ifreqt2(c2)
>>> c3
tensor([ 0.0682, 0.4790, -1.0168, -0.6026, 0.1094])
"""
c2 = torch.matmul(c1, self.A)
return c2