def spectrogram(samples, sample_rate, frame_len, fps, batch=50):
"""
Computes a magnitude spectrogram for a given vector of samples at a given
sample rate (in Hz), frame length (in samples) and frame rate (in Hz).
Allows to transform multiple frames at once for improved performance (with
a default value of 50, more is not always better). Returns a numpy array.
"""
if len(samples) < frame_len:
return np.empty((0, frame_len // 2 + 1), dtype=samples.dtype)
win = np.hanning(frame_len)
hopsize = sample_rate // fps
num_frames = max(0, (len(samples) - frame_len) // hopsize + 1)
batch = min(batch, num_frames)
if batch <= 1 or not samples.flags.c_contiguous:
rfft = rfft_builder(samples[:frame_len], n=frame_len)
spect = np.vstack(np.abs(rfft(samples[pos:pos + frame_len] * win))
for pos in range(0, len(samples) - frame_len + 1,
int(hopsize)))
else:
rfft = rfft_builder(np.empty((batch, frame_len), samples.dtype),
n=frame_len, threads=1)
frames = np.lib.stride_tricks.as_strided(
samples, shape=(num_frames, frame_len),
strides=(samples.strides[0] * hopsize, samples.strides[0]))
spect = [np.abs(rfft(frames[pos:pos + batch] * win))
for pos in range(0, num_frames - batch + 1, batch)]
if num_frames % batch:
spect.extend(spectrogram(
samples[(num_frames // batch * batch) * hopsize:],
sample_rate, frame_len, fps, batch=1))
spect = np.vstack(spect)
return spect
评论列表
文章目录