GAN_BWE / utils /audio.py
harshil09's picture
uploaded
803f0fe verified
Raw
History Blame Contribute Delete
3.13 kB
import torch
import torch.nn as nn
import torch.nn.functional as F
def wav_to_spec(
wav: torch.Tensor,
fft_size: int,
hop_length: int,
win_length: int,
window: torch.Tensor = None
) -> tuple[torch.Tensor, torch.Tensor]:
"""Convert waveform to magnitude and phase spectrograms.
Args:
wav: Time-domain signal tensor of shape (batch, 1, samples) or (batch, samples).
fft_size: FFT window size.
hop_length: Hop length between frames.
win_length: Analysis window length.
window: Pre-created window tensor (optional).
Returns:
magnitude: Magnitude spectrogram tensor.
phase: Phase spectrogram tensor.
"""
if wav.dim() == 3:
wav = wav.squeeze(1) # (batch, samples)
if window is None:
window = torch.hann_window(win_length, device=wav.device)
# STFT returns a complex tensor
stft = torch.stft(
wav,
n_fft=fft_size,
hop_length=hop_length,
win_length=win_length,
window=window,
center=True,
pad_mode='reflect',
normalized=False,
onesided=True,
return_complex=True
)
magnitude = torch.abs(stft)
phase = torch.angle(stft)
return magnitude, phase
def spec_to_wav(
magnitude: torch.Tensor,
phase: torch.Tensor,
fft_size: int,
hop_length: int,
win_length: int,
window: torch.Tensor = None
) -> torch.Tensor:
"""Convert magnitude and phase spectrograms back to time-domain waveform.
Args:
magnitude: Magnitude spectrogram tensor.
phase: Phase spectrogram tensor.
fft_size: FFT window size.
hop_length: Hop length between frames.
win_length: Analysis window length.
window: Pre-created window tensor (optional).
Returns:
wav: Reconstructed time-domain waveform of shape (batch, samples).
"""
if window is None:
window = torch.hann_window(win_length, device=magnitude.device)
# Reconstruct complex spectrogram
stft = torch.polar(magnitude, phase)
wav = torch.istft(
stft,
n_fft=fft_size,
hop_length=hop_length,
win_length=win_length,
window=window,
center=True,
normalized=False,
onesided=True
)
return wav.unsqueeze(1) # (batch, 1, samples)
def pad_to_multiple(wav: torch.Tensor, multiple: int) -> torch.Tensor:
"""Pad waveform time-dimension to be a multiple of a given divisor.
Args:
wav: Tensor of shape (batch, channels, samples) or (batch, samples).
multiple: The integer the length should be a multiple of.
Returns:
Padded tensor.
"""
length = wav.shape[-1]
remainder = length % multiple
if remainder == 0:
return wav
pad_len = multiple - remainder
pad_left = pad_len // 2
pad_right = pad_len - pad_left
# F.pad expects padding list in reverse order of dimensions (last dim padding: left, right)
return F.pad(wav, (pad_left, pad_right), mode='reflect')