• 文件 >
  • 減法合成 >
  • 舊版本 (穩定版)
快捷方式

減法合成

作者: Moto Hira

本教程是濾波器設計教程的延續。

本教程展示瞭如何使用 TorchAudio 的 DSP 函式執行減法合成。

減法合成透過對源波形應用濾波器來建立音色。

警告

本教程需要原型 DSP 特性,這些特性可在每夜構建版本中使用。

請參考https://pytorch.com.tw/get-started/locally檢視安裝每夜構建版本的說明。

import torch
import torchaudio

print(torch.__version__)
print(torchaudio.__version__)
2.7.0
2.7.0

概述

try:
    from torchaudio.prototype.functional import filter_waveform, frequency_impulse_response, sinc_impulse_response
except ModuleNotFoundError:
    print(
        "Failed to import prototype DSP features. "
        "Please install torchaudio nightly builds. "
        "Please refer to https://pytorch.com.tw/get-started/locally "
        "for instructions to install a nightly build."
    )
    raise

import matplotlib.pyplot as plt
from IPython.display import Audio

濾波噪聲

減法合成從波形開始,並對某些頻率分量應用濾波器。

對於減法合成的第一個示例,我們將時變低通濾波器應用於白噪聲。

首先,我們建立一個白噪聲。

def plot_input():
    fig, axes = plt.subplots(2, 1, sharex=True)
    t = torch.linspace(0, duration, num_frames)
    axes[0].plot(t, noise)
    axes[0].grid(True)
    axes[1].specgram(noise, Fs=SAMPLE_RATE)
    Audio(noise, rate=SAMPLE_RATE)


plot_input()
subtractive synthesis tutorial

加窗 sinc 濾波器

掃描截止頻率

我們使用sinc_impulse_response()來建立一系列低通濾波器,同時將截止頻率從零更改為奈奎斯特頻率。

num_filters = 64 * duration
window_size = 2049

f_cutoff = torch.linspace(0.0, 0.8, num_filters)
kernel = sinc_impulse_response(f_cutoff, window_size)

要應用時變濾波器,我們使用filter_waveform()

filtered = filter_waveform(noise, kernel)

讓我們看看生成音訊的頻譜圖並聽一下。

def plot_sinc_ir(waveform, cutoff, sample_rate, vol=0.2):
    num_frames = waveform.size(0)
    duration = num_frames / sample_rate
    num_cutoff = cutoff.size(0)
    nyquist = sample_rate / 2

    _, axes = plt.subplots(2, 1, sharex=True)
    t = torch.linspace(0, duration, num_frames)
    axes[0].plot(t, waveform)
    axes[0].grid(True)
    axes[1].specgram(waveform, Fs=sample_rate, scale="dB")
    t = torch.linspace(0, duration, num_cutoff)
    axes[1].plot(t, cutoff * nyquist, color="gray", linewidth=0.8, label="Cutoff Frequency", linestyle="--")
    axes[1].legend(loc="upper center")
    axes[1].set_ylim([0, nyquist])
    waveform /= waveform.abs().max()
    return Audio(vol * waveform, rate=sample_rate, normalize=False)
plot_sinc_ir(filtered, f_cutoff, SAMPLE_RATE)
subtractive synthesis tutorial


振盪截止頻率

透過振盪截止頻率,我們可以模擬低頻振盪 (LFO) 的效果。

kernel = sinc_impulse_response(f_cutoff, window_size)
filtered = filter_waveform(noise, kernel)
plot_sinc_ir(filtered, f_cutoff, SAMPLE_RATE)
subtractive synthesis tutorial


哇音效果

哇音效果是低通濾波器或帶通濾波器的應用。它們會快速改變截止頻率或 Q 因子。

f_lfo = torch.linspace(0.15, 0.15, num_filters)
f_cutoff = 0.07 + 0.06 * torch.sin(torch.cumsum(f_lfo, dim=0))
kernel = sinc_impulse_response(f_cutoff, window_size)
filtered = filter_waveform(noise, kernel)
plot_sinc_ir(filtered, f_cutoff, SAMPLE_RATE)
subtractive synthesis tutorial


任意頻率響應

透過使用frequency_impulse_response(),可以直接控制頻率上的功率分佈。

magnitudes = torch.sin(torch.linspace(0, 10, 64)) ** 4.0
kernel = frequency_impulse_response(magnitudes)
filtered = filter_waveform(noise, kernel.unsqueeze(0))
def plot_waveform(magnitudes, filtered, sample_rate):
    nyquist = sample_rate / 2
    num_samples = filtered.size(-1)
    duration = num_samples / sample_rate

    # Re-organize magnitudes for overlay
    N = 10  # number of overlays
    interval = torch.linspace(0.05, 0.95, N)
    offsets = duration * interval
    # Select N magnitudes for overlays
    mags = torch.stack(
        [magnitudes for _ in range(N)]
        if magnitudes.ndim == 1
        else [magnitudes[int(i * magnitudes.size(0))] for i in interval]
    )
    mag_x = offsets.unsqueeze(-1) + 0.1 * mags
    mag_y = torch.linspace(0, nyquist, magnitudes.size(-1)).tile((N, 1))

    _, ax = plt.subplots(1, 1, sharex=True)
    ax.vlines(offsets, 0, nyquist, color="gray", linestyle="--", linewidth=0.8)
    ax.plot(mag_x.T.numpy(), mag_y.T.numpy(), color="gray", linewidth=0.8)
    ax.specgram(filtered, Fs=sample_rate)
    return Audio(filtered, rate=sample_rate)
plot_waveform(magnitudes, filtered, SAMPLE_RATE)
subtractive synthesis tutorial


也可以建立非平穩濾波器。

magnitudes = torch.stack([torch.linspace(0.0, w, 1000) for w in torch.linspace(4.0, 40.0, 250)])
magnitudes = torch.sin(magnitudes) ** 4.0
kernel = frequency_impulse_response(magnitudes)
filtered = filter_waveform(noise, kernel)
plot_waveform(magnitudes, filtered, SAMPLE_RATE)
subtractive synthesis tutorial


當然也可以模擬簡單的低通濾波器。

kernel = frequency_impulse_response(magnitudes)
filtered = filter_waveform(noise, kernel.unsqueeze(0))
plot_waveform(magnitudes, filtered, SAMPLE_RATE)
subtractive synthesis tutorial


參考文獻

指令碼總執行時間: ( 0 分鐘 8.016 秒)

由 Sphinx-Gallery 生成的相簿

文件

訪問 PyTorch 的全面開發者文件

檢視文件

教程

獲取面向初學者和高階開發者的深度教程

檢視教程

資源

查詢開發資源並獲得問題解答

檢視資源