Author: Moto Hira
This tutorial is the continuation of Filter Design Tutorial.
This tutorial shows how to perform subtractive synthesis with TorchAudio’s DSP functions.
Subtractive synthesis creates timbre by applying filters to source waveform.
This tutorial requires prototype DSP features, which are available in nightly builds.
Please refer to https://pytorch.org/get-started/locally for instructions for installing a nightly build.
import torch import torchaudio print(torch.__version__) print(torchaudio.__version__)
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.org/get-started/locally " "for instructions to install a nightly build." ) raise import matplotlib.pyplot as plt from IPython.display import Audio
Subtractive synthesis starts with a waveform and applies filters to some frequency components.
For the first example of subtractive synthesis, we apply time-varying low pass filter to white noise.
First, we create a white noise.
Sweeping cutoff frequency¶
create series of low pass filters, while changing the cut-off
frequency from zero to Nyquist frequency.
To apply time-varying filter, we use
Let’s look at the spectrogram of the resulting audio and listen to it.
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.plot(t, waveform) axes.grid(True) axes.specgram(waveform, Fs=sample_rate, scale="dB") t = torch.linspace(0, duration, num_cutoff) axes.plot(t, cutoff * nyquist, color="gray", linewidth=0.8, label="Cutoff Frequency", linestyle="--") axes.legend(loc="upper center") axes.set_ylim([0, nyquist]) waveform /= waveform.abs().max() return Audio(vol * waveform, rate=sample_rate, normalize=False)
Oscillating cutoff frequency¶
By oscillating the cutoff frequency, we can emulate an effect of Low-frequency oscillation (LFO).
Wah-wah effects are applications of low-pass filter or band-pass filter. They change the cut-off freuqnecy or Q-factor quickly.
Arbitrary frequence response¶
one can directly control the power distribution over frequency.
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)
It is also possible to make a non-stationary filter.
Of course it is also possible to emulate simple low pass filter.