Compute the Inverse Short Time Fourier Transform (ISTFT) of a complex spectrogram. Args: spec (Tensor): Input complex spectrogram of shape (B, N, T), where B is the batch size, N is the number of frequency bins, and T is the number of time fr
(self, spec: torch.Tensor)
| 348 | self.register_buffer("window", window) |
| 349 | |
| 350 | def forward(self, spec: torch.Tensor) -> torch.Tensor: |
| 351 | """ |
| 352 | Compute the Inverse Short Time Fourier Transform (ISTFT) of a complex spectrogram. |
| 353 | |
| 354 | Args: |
| 355 | spec (Tensor): Input complex spectrogram of shape (B, N, T), where B is the batch size, |
| 356 | N is the number of frequency bins, and T is the number of time frames. |
| 357 | |
| 358 | Returns: |
| 359 | Tensor: Reconstructed time-domain signal of shape (B, L), where L is the length of the output signal. |
| 360 | """ |
| 361 | if self.padding == "center": |
| 362 | # Fallback to pytorch native implementation |
| 363 | return torch.istft( |
| 364 | spec, |
| 365 | self.n_fft, |
| 366 | self.hop_length, |
| 367 | self.win_length, |
| 368 | self.window, |
| 369 | center=True, |
| 370 | ) |
| 371 | elif self.padding == "same": |
| 372 | pad = (self.win_length - self.hop_length) // 2 |
| 373 | else: |
| 374 | raise ValueError("Padding must be 'center' or 'same'.") |
| 375 | |
| 376 | assert spec.dim() == 3, "Expected a 3D tensor as input" |
| 377 | B, N, T = spec.shape |
| 378 | |
| 379 | # Inverse FFT |
| 380 | ifft = torch.fft.irfft(spec, self.n_fft, dim=1, norm="backward") |
| 381 | ifft = ifft * self.window[None, :, None] |
| 382 | |
| 383 | # Overlap and Add |
| 384 | output_size = (T - 1) * self.hop_length + self.win_length |
| 385 | y = torch.nn.functional.fold( |
| 386 | ifft, |
| 387 | output_size=(1, output_size), |
| 388 | kernel_size=(1, self.win_length), |
| 389 | stride=(1, self.hop_length), |
| 390 | )[:, 0, 0, pad:-pad] |
| 391 | |
| 392 | # Window envelope |
| 393 | window_sq = self.window.square().expand(1, T, -1).transpose(1, 2) |
| 394 | window_envelope = torch.nn.functional.fold( |
| 395 | window_sq, |
| 396 | output_size=(1, output_size), |
| 397 | kernel_size=(1, self.win_length), |
| 398 | stride=(1, self.hop_length), |
| 399 | ).squeeze()[pad:-pad] |
| 400 | |
| 401 | # Normalize |
| 402 | assert (window_envelope > 1e-11).all() |
| 403 | y = y / window_envelope |
| 404 | |
| 405 | return y |
| 406 | |
| 407 | def forward_chunk( |
no outgoing calls
no test coverage detected