Code
def gliding_target(dur=2.0):
"""A harmonic complex gliding 150 -> 250 Hz with a 3 Hz level fluctuation: a stand-in for speech."""
t = np.arange(int(dur * FS)) / FS
phase = 2 * np.pi * np.cumsum(150 + 50 * t) / FS
target = so.Sound(sum(np.cos(k * phase) / k for k in range(1, 30)), FS).normalize()
return (target * (0.6 + 0.4 * np.sin(2 * np.pi * 3 * t))).ramp(20e-3)
def show_mask(snd, target, mask):
"""Waveform, the mask, and spectrograms of this sound and of the target alone.
Returns the figure and the panels the playhead follows."""
fig, axes = plt.subplots(2, 2, figsize=(10, 6.2), sharex=True, layout="constrained")
snd.plot(axes[0, 0], lw=0.4)
axes[0, 0].set_title("Waveform")
mask.plot(axes[0, 1])
axes[0, 1].set(title="Ideal binary mask (target > noise)", ylim=(0, 5))
so.STFT(snd, 25e-3).plot(axes[1, 0], fmax=5000, colorbar=False)
axes[1, 0].set_title("Spectrogram of this sound")
so.STFT(target, 25e-3).plot(axes[1, 1], fmax=5000, colorbar=False)
axes[1, 1].set_title("The target alone (not played)")
return fig, [axes[0, 0], axes[1, 0]]
target = gliding_target()
masker = so.gaussian_noise(target.duration, FS, tilt=-3, rng=0)
mixture = target + (masker + 5 * dB)
S_t, S_m, S_x = (so.STFT(x, 25e-3) for x in (target, masker, mixture))
mask = so.ideal_binary_mask(S_t, S_m, lc_db=0)