本文对 Librosa、Madmom 和 Torchaudio 三个库中获取频谱图的方法细节进行对比。
分帧细节对比
librosa
参数设置举例
1 2 3 4 5 6 7 8 sample_rate = 22050 n_fft = 1764 win_length = n_fft hop_length = 441 center = True duration = 1 num_samples = sample_rate * duration random_audio = np.random.randn(num_samples)
短时傅里叶变换
librosa.stft
1 2 3 4 5 6 7 D = librosa.stft( random_audio, n_fft=n_fft, hop_length=hop_length, win_length=win_length, center=center )
mel频谱图
librosa.feature.melspectrogram
1 2 3 4 5 6 7 8 mel_spectrogram = librosa.feature.melspectrogram( y=random_audio, sr=sample_rate, n_fft=n_fft, hop_length=hop_length, win_length=win_length, center=center )
分帧实验
输出 D 或 mel_spectrogram 的形状我们可以得到变换后的帧数,以下是使用不同参数得到的帧数,该部分数据可用于验证帧数计算公式是否正确。
实验数据
center
win_length
hop_length
num_sampless
num_frames
true
1764
441
22050
51
true
1764
441
22049
50
true
1764
441
22051
51
true
1763
441
22050
50
true
1763
441
22049
50
true
1763
441
22051
51
true
1765
441
22050
50
true
1765
441
22049
50
true
1765
441
22051
51
true
1764
441
44100
101
true
1764
441
44099
100
true
1764
441
44101
101
true
1763
441
44100
100
true
1763
441
44099
100
true
1763
441
44101
101
true
1765
441
44100
100
true
1765
441
44099
100
true
1765
441
44101
101
center
win_length
hop_length
num_sampless
num_frames
false
1764
441
22050
47
false
1764
441
22049
46
false
1764
441
22051
47
false
1763
441
22050
47
false
1763
441
22049
47
false
1763
441
22051
47
false
1765
441
22050
46
false
1765
441
22049
46
false
1765
441
22051
47
false
1764
441
44100
97
false
1764
441
44099
96
false
1764
441
44101
97
false
1763
441
44100
97
false
1763
441
44099
97
false
1763
441
44101
97
false
1765
441
44100
96
false
1765
441
44099
96
false
1765
441
44101
97
madmom
对信号分帧
madmom.audio.signal.FramedSignal
1 2 3 4 5 6 7 8 frames = madmom.audio.signal.FramedSignal( random_audio, frame_size=win_length, hop_size=hop_length, end='normal' , sample_rate=sample_rate, origin=center )
频谱图
madmom.audio.spectrogram.Spectrogram
1 2 3 4 5 6 7 8 9 spectrogram = madmom.audio.spectrogram.Spectrogram( random_audio, n_fft=n_fft, frame_size=win_length, hop_size=hop_length, end='normal' , sample_rate=sample_rate, origin=center )
分帧实验
输出 frames 或 spectrogram 的形状我们可以得到变换后的帧数,以下是使用不同参数得到的帧数。
实验数据
origin
win_length
hop_length
num_sampless
num_frames
center
1764
441
22050
50
center
1764
441
22049
50
center
1764
441
22051
51
center
1763
441
22050
50
center
1763
441
22049
50
center
1763
441
22051
51
center
1765
441
22050
50
center
1765
441
22049
50
center
1765
441
22051
51
center
1764
441
44100
100
center
1764
441
44099
100
center
1764
441
44101
101
center
1763
441
44100
100
center
1763
441
44099
100
center
1763
441
44101
101
center
1765
441
44100
100
center
1765
441
44099
100
center
1765
441
44101
101
origin
win_length
hop_length
num_sampless
num_frames
future
1764
441
22050
50
future
1764
441
22049
50
future
1764
441
22051
51
future
1763
441
22050
50
future
1763
441
22049
50
future
1763
441
22051
51
future
1765
441
22050
50
future
1765
441
22049
50
future
1765
441
22051
51
future
1764
441
44100
100
future
1764
441
44099
100
future
1764
441
44101
101
future
1763
441
44100
100
future
1763
441
44099
100
future
1763
441
44101
101
future
1765
441
44100
100
future
1765
441
44099
100
future
1765
441
44101
101
结论
由 madmom.audio.signal.FramedSignal 中的代码
1 num_frames = np.ceil(len (self.signal) / float (self.hop_size))
以及实验数据可得帧数计算公式:
N f r a m e s = ⌈ N s a m p l e s h o p _ s i z e ⌉ N_{frames}=\left\lceil\frac{N_{samples}}{hop\_size}\right\rceil
N f r a m e s = ⌈ h o p _ s i z e N s a m p l e s ⌉
由 madmom.audio.signal.FramedSignal 中的代码
1 2 self.hop_size = self.signal.sample_rate / float (fps)
可得帧率计算公式:
f p s = s a m p l e _ r a t e h o p _ s i z e fps = \frac{sample\_rate} {hop\_size}
f p s = h o p _ s i z e s a m p l e _ r a t e
torchaudio
频谱图
torchaudio.transforms.Spectrogram
1 2 3 4 5 6 7 8 random_audio = torch.randn(1 , num_samples) trans_spectrogram = torchaudio.transforms.Spectrogram( n_fft=n_fft, win_length=win_length, hop_length=hop_length, center=center ) spectrogram = trans_spectrogram(random_audio)
mel频谱图
torchaudio.transforms.MelSpectrogram
1 2 3 4 5 6 7 8 trans_mel_spectrogram = torchaudio.transforms.MelSpectrogram( sample_rate=sample_rate, n_fft=n_fft, win_length=win_length, hop_length=hop_length, center=center ) mel_spectrogram = trans_mel_spectrogram(random_audio)
分帧实验
输出 spectrogram 或 mel_spectrogram 的形状我们可以得到变换后的帧数,以下是使用不同参数得到的帧数。
实验数据
center
win_length
hop_length
num_sampless
num_frames
true
1764
441
22050
51
true
1764
441
22049
50
true
1764
441
22051
51
true
1763
441
22050
50
true
1763
441
22049
50
true
1763
441
22051
51
true
1765
441
22050
50
true
1765
441
22049
50
true
1765
441
22051
51
true
1764
441
44100
101
true
1764
441
44099
100
true
1764
441
44101
101
true
1763
441
44100
100
true
1763
441
44099
100
true
1763
441
44101
101
true
1765
441
44100
100
true
1765
441
44099
100
true
1765
441
44101
101
center
win_length
hop_length
num_sampless
num_frames
false
1764
441
22050
47
false
1764
441
22049
46
false
1764
441
22051
47
false
1763
441
22050
47
false
1763
441
22049
47
false
1763
441
22051
47
false
1765
441
22050
46
false
1765
441
22049
46
false
1765
441
22051
47
false
1764
441
44100
97
false
1764
441
44099
96
false
1764
441
44101
97
false
1763
441
44100
97
false
1763
441
44099
97
false
1763
441
44101
97
false
1765
441
44100
96
false
1765
441
44099
96
false
1765
441
44101
97
在本实验所使用的参数设置下,torchaudio 与 librosa 分帧帧数一致。
时间与帧的对应关系
librosa
根据 librosa.time_to_frames 可知对应关系为:
1 frames[i] = floor( times[i] * sr / hop_length )
根据源代码 ,实现 time_to_frames 时,使用 time_to_samples 和 samples_to_frames 进行转换。
根据 librosa.frames_to_time 可知对应关系为:
1 times[i] = frames[i] * hop_length / sr
根据源代码 ,实现 frames_to_time 时,使用 frames_to_samples 和 samples_to_time 进行转换。
以上函数中还有n_fft参数,librosa.frames_to_time 中的解释为“If given, time conversion will include an offset of n_fft // 2 to counteract windowing effects when using a non-centered STFT.”, librosa.time_to_frames 中的解释为“If given, time conversion will include an offset of - n_fft // 2 to counteract windowing effects in STFT.”。 根据以上解释,可推测在使用“center”的时频变换的情况下,调用 frames_to_time 和 time_to_frames 函数不需要 n_fft 参数。
根据以上两段代码可以推测,虽然 librosa 没有对帧率(fps)进行定义,但实现时是隐式使用 sr / hop_length 作为 fps 的。
madmom
根据madmom.utils.quantize_events 的代码
1 2 3 4 5 events *= fps idx = np.unique(np.round (events).astype(np.int )) quantized[idx] = 1
可知对应关系为:
1 frames[i] = round(times[i] * fps)