Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mdst #87

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions diffsptk/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,29 @@ def imdct(y, out_length=None, frame_length=400, window="sine"):
)


def imdst(y, out_length=None, frame_length=400, window="sine"):
"""Compute inverse modified discrete sine transform.

Parameters
----------
y : Tensor [shape=(..., 2T/L, L/2)]
Spectrum.

out_length : int or None
Length of output waveform.

frame_length : int >= 2
Frame length, :math:`L`.

window : ['sine', 'vorbis', 'kbd', 'rectangular']
Window type.

"""
return nn.InverseModifiedDiscreteSineTransform._func(
y, out_length=out_length, frame_length=frame_length, window=window
)


def interpolate(x, period=1, start=0, dim=-1):
"""Interpolate signal.

Expand Down Expand Up @@ -1349,6 +1372,31 @@ def mdct(x, frame_length=400, window="sine"):
)


def mdst(x, frame_length=400, window="sine"):
"""Compute modified discrete sine transform.

Parameters
----------
x : Tensor [shape=(..., T)]
Waveform.

frame_length : int >= 2
Frame length, :math:`L`.

window : ['sine', 'vorbis', 'kbd', 'rectangular']
Window type.

Returns
-------
out : Tensor [shape=(..., 2T/L, L/2)]
Spectrum.

"""
return nn.ModifiedDiscreteSineTransform._func(
x, frame_length=frame_length, window=window
)


def mgc2mgc(
mc,
out_order,
Expand Down
4 changes: 4 additions & 0 deletions diffsptk/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
from .ignorm import GeneralizedCepstrumInverseGainNormalization
from .imdct import InverseModifiedDiscreteCosineTransform
from .imdct import InverseModifiedDiscreteCosineTransform as IMDCT
from .imdst import InverseModifiedDiscreteSineTransform
from .imdst import InverseModifiedDiscreteSineTransform as IMDST
from .imglsadf import PseudoInverseMGLSADigitalFilter
from .imglsadf import PseudoInverseMGLSADigitalFilter as IMLSA
from .imsvq import InverseMultiStageVectorQuantization
Expand Down Expand Up @@ -77,6 +79,8 @@
from .mcpf import MelCepstrumPostfiltering
from .mdct import ModifiedDiscreteCosineTransform
from .mdct import ModifiedDiscreteCosineTransform as MDCT
from .mdst import ModifiedDiscreteSineTransform
from .mdst import ModifiedDiscreteSineTransform as MDST
from .mfcc import MelFrequencyCepstralCoefficientsAnalysis
from .mfcc import MelFrequencyCepstralCoefficientsAnalysis as MFCC
from .mgc2mgc import MelGeneralizedCepstrumToMelGeneralizedCepstrum
Expand Down
2 changes: 1 addition & 1 deletion diffsptk/modules/dct.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,5 @@ def _precompute(length, dtype=None, device=None):
k = torch.arange(L, dtype=torch.double, device=device)
n = (torch.pi / L) * (k + 0.5)
z = torch.sqrt(torch.clip(k + 1, min=1, max=2) / L)
W = z.unsqueeze(0) * torch.cos(k.unsqueeze(0) * n.unsqueeze(1))
W = z * torch.cos(k.unsqueeze(0) * n.unsqueeze(1))
return to(W, dtype=dtype)
2 changes: 1 addition & 1 deletion diffsptk/modules/dst.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,5 @@ def _precompute(length, dtype=None, device=None):
k = torch.arange(L, dtype=torch.double, device=device) + 1
n = (torch.pi / L) * (k - 0.5)
z = torch.sqrt(torch.clip(k, min=1, max=2) / L).flip(0)
W = z.unsqueeze(0) * torch.sin(k.unsqueeze(0) * n.unsqueeze(1))
W = z * torch.sin(k.unsqueeze(0) * n.unsqueeze(1))
return to(W, dtype=dtype)
55 changes: 29 additions & 26 deletions diffsptk/modules/imdct.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from torch import nn

from ..misc.utils import check_size
from .mdct import ModifiedDiscreteCosineTransformCore as MDCT
from .mdct import ModifiedDiscreteTransform
from .unframe import Unframe
from .window import Window

Expand All @@ -36,14 +36,12 @@ class InverseModifiedDiscreteCosineTransform(nn.Module):

"""

def __init__(self, frame_length, window="sine"):
def __init__(self, frame_length, window="sine", **kwargs):
super().__init__()

self.frame_period = frame_length // 2

self.imdct = InverseModifiedDiscreteCosineTransformCore(
frame_length, window != "rectangular"
)
self.imdct = InverseModifiedDiscreteTransform(frame_length, window, **kwargs)
self.window = Window(frame_length, window=window, norm="none")
self.unframe = Unframe(frame_length, self.frame_period)

Expand Down Expand Up @@ -84,9 +82,9 @@ def forward(self, y, out_length=None):
return x

@staticmethod
def _func(y, out_length, frame_length, window):
def _func(y, out_length, frame_length, window, **kwargs):
frame_period = frame_length // 2
x = InverseModifiedDiscreteCosineTransformCore._func(y, window != "rectangular")
x = InverseModifiedDiscreteTransform._func(y, window, **kwargs)
x = Window._func(x, None, window=window, norm="none")
x = Unframe._func(
x,
Expand All @@ -102,30 +100,33 @@ def _func(y, out_length, frame_length, window):
return x


class InverseModifiedDiscreteCosineTransformCore(nn.Module):
"""Inverse modified discrete cosine transform module.
class InverseModifiedDiscreteTransform(nn.Module):
"""Inverse modified discrete cosine/sine transform module.

Parameters
----------
dct_length : int >= 2
DCT length, :math:`L`.
length : int >= 2
Output length, :math:`L`.

windowed : bool
window : bool or str
If True, assume that input is windowed.

transform : ['cosine', 'sine']
Transform type.

"""

def __init__(self, dct_length, windowed=False):
def __init__(self, length, window, transform="cosine"):
super().__init__()

assert 2 <= dct_length
assert dct_length % 2 == 0
assert 2 <= length
assert length % 2 == 0

self.dct_length = dct_length
self.register_buffer("W", self._precompute(self.dct_length, windowed))
self.length = length
self.register_buffer("W", self._precompute(length, window, transform))

def forward(self, y):
"""Apply inverse MDCT to input.
"""Apply inverse MDCT/MDST to input.

Parameters
----------
Expand All @@ -135,23 +136,25 @@ def forward(self, y):
Returns
-------
out : Tensor [shape=(..., L)]
Inverse MDCT output.
Output.

"""
check_size(2 * y.size(-1), self.dct_length, "dimension of input")
check_size(2 * y.size(-1), self.length, "dimension of input")
return self._forward(y, self.W)

@staticmethod
def _forward(y, W):
return torch.matmul(y, W)

@staticmethod
def _func(y, windowed):
W = InverseModifiedDiscreteCosineTransformCore._precompute(
2 * y.size(-1), windowed, dtype=y.dtype, device=y.device
def _func(y, window, **kwargs):
W = InverseModifiedDiscreteTransform._precompute(
2 * y.size(-1), window, dtype=y.dtype, device=y.device, **kwargs
)
return InverseModifiedDiscreteCosineTransformCore._forward(y, W)
return InverseModifiedDiscreteTransform._forward(y, W)

@staticmethod
def _precompute(length, windowed, dtype=None, device=None):
return MDCT._precompute(length, windowed, dtype=dtype, device=device).T
def _precompute(length, window, transform="cosine", dtype=None, device=None):
return ModifiedDiscreteTransform._precompute(
length, window, transform, dtype=dtype, device=device
).T
73 changes: 73 additions & 0 deletions diffsptk/modules/imdst.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# ------------------------------------------------------------------------ #
# 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. #
# ------------------------------------------------------------------------ #

from torch import nn

from .imdct import InverseModifiedDiscreteCosineTransform as IMDST


class InverseModifiedDiscreteSineTransform(nn.Module):
"""This is the opposite module to :func:`~diffsptk.ModifiedDiscreteSineTransform`.

Parameters
----------
frame_length : int >= 2
Frame length, :math:`L`.

window : ['sine', 'vorbis', 'kbd', 'rectangular']
Window type.

"""

def __init__(self, frame_length, window="sine"):
super().__init__()

self.imdst = IMDST(frame_length, window, transform="sine")

def forward(self, y, out_length=None):
"""Compute inverse modified discrete sine transform.

Parameters
----------
y : Tensor [shape=(..., 2T/L, L/2)]
Spectrum.

out_length : int or None
Length of output waveform.

Returns
-------
out : Tensor [shape=(..., T)]
Reconstructed waveform.

Examples
--------
>>> x = diffsptk.ramp(3)
>>> x
tensor([0., 1., 2., 3.])
>>> mdst_params = {"frame_length": 4}
>>> mdst = diffsptk.MDST(**mdst_params)
>>> imdst = diffsptk.IMDST(**mdst_params)
>>> y = imdst(mdst(x))
>>> y
tensor([-8.9407e-08, 1.0000e+00, 2.0000e+00, 3.0000e+00])

"""
return self.imdst(y, out_length=out_length)

@staticmethod
def _func(y, out_length, frame_length, window):
return IMDST._func(y, out_length, frame_length, window, transform="sine")
Loading