"""Spectrogram features of the dataset clips, cached on disk. Each clip becomes a log-magnitude spectrogram in dB relative to its own maximum, floored at -80 dB and scaled to [0, 1], over 0 to FMAX Hz. The level of the clip therefore does not enter (the WAVs are peak-normalized anyway). The frequency resolution matters more than the time resolution here: the sheet's low partials are tens of hertz apart and ring for seconds, so the window is long (N_FFT / 48000 = 171 ms) and the hop coarse (21 ms). """ import json import os import sys import wave from concurrent.futures import ProcessPoolExecutor import numpy as np FS = 48000 N_FFT = 8192 HOP = 1024 FMAX = 6000.0 DB_FLOOR = 80.0 N_BINS = int(FMAX / FS * N_FFT) # 1024 bins of 5.86 Hz # Log-frequency variant: 48 bins per octave over 8 octaves from F_LO. On this # axis a change of the sheet's frequency scale (kappa / L^2) translates the # whole pattern of partials, which a convolutional network detects naturally. F_LO = 20.0 BINS_PER_OCTAVE = 48 N_LOGF = 8 * BINS_PER_OCTAVE def read_wav(path): with wave.open(path) as w: assert w.getnchannels() == 1 and w.getsampwidth() == 2 and w.getframerate() == FS, path x = np.frombuffer(w.readframes(w.getnframes()), dtype="