使用Librosa提取节拍时间戳处音频振幅的方法正确性验证
使用Librosa提取节拍时间戳处音频振幅的方法正确性验证
嘿,你的思路大方向是对的,但中间多了一步没必要的转换,这会导致结果出错!我来帮你梳理清楚正确的做法,再给你几个实用的验证方法~
先说说你的方法问题在哪
你当前的步骤是:
beats_to_samples = librosa.time_to_samples(beats, sr=sample_rate) beat_samples_to_frames = librosa.samples_to_frames(beats_to_samples ) signal_strength_at_beats_timestamps = audio_signal[beat_samples_to_frames]
这里的问题出在**samples_to_frames()这一步**:
audio_signal是采样点级别的数组,每个索引对应一个采样点(和时间的关系是时间 = 索引 / 采样率),直接用beats_to_samples的结果去索引audio_signal才是正确的。- 而
frames(帧)是Librosa做特征提取(比如STFT、梅尔频谱)时的分块单位,默认帧长2048、步长512,帧索引和采样点索引完全不是一个概念,转成帧索引后去取audio_signal的元素,相当于取了完全错误的位置,结果自然不对。
正确的提取方法
直接去掉转帧的步骤就可以了:
# 把节拍时间(秒)转成采样点索引 beat_samples = librosa.time_to_samples(beats_timestamps, sr=sample_rate) # 直接用采样点索引提取对应位置的振幅 signal_strength = audio_signal[beat_samples]
这一步的逻辑是完全通顺的:采样率代表每秒有多少个采样点,所以时间戳乘以采样率就得到该时间点对应的采样点在数组中的位置,直接索引就能拿到对应振幅。
如何验证结果是否正确
给你三个简单靠谱的验证方法:
1. 手动计算对比
比如你的采样率是44100Hz,那1.22秒对应的采样点是1.22 * 44100 ≈ 53802,你可以手动计算这个值,然后和librosa.time_to_samples(1.22, sr=44100)的输出对比,看是否一致。之后直接取audio_signal[53802],和你之前错误方法得到的值对比,就能明显看出差异。
2. 可视化直观确认
用Matplotlib把音频波形画出来,然后在节拍时间戳对应的位置标记竖线和振幅值,一眼就能看对不对:
import matplotlib.pyplot as plt # 绘制音频波形 plt.figure(figsize=(12, 4)) plt.plot(audio_signal) # 转换节拍时间到采样点索引 beat_samples = librosa.time_to_samples(beats_timestamps, sr=sample_rate) # 在每个节拍位置画红色虚线,并标注振幅值 for idx in beat_samples: plt.axvline(x=idx, color='r', linestyle='--', alpha=0.7) plt.text(idx, audio_signal[idx], f'{audio_signal[idx]:.4f}', color='r', fontsize=10, ha='center') plt.xlabel('采样点索引') plt.ylabel('振幅') plt.title('节拍位置对应的音频振幅') plt.show()
如果提取的振幅值和波形上对应位置的数值一致,那就说明方法正确。
3. 用自定义测试音频验证
自己生成一个带明确脉冲的音频,比如在1秒、2秒、3秒位置设置固定振幅的脉冲,然后用你的方法提取,看是否能得到预期值:
import numpy as np # 生成测试音频:采样率44100,时长4秒,大部分为0,指定时间点有脉冲 sr = 44100 duration = 4 test_audio = np.zeros(sr * duration) # 在1秒位置设振幅为1,2秒为1.5,3秒为2 test_audio[sr * 1] = 1 test_audio[sr * 2] = 1.5 test_audio[sr * 3] = 2 # 节拍时间戳就是这三个时间点 test_beats = [1, 2, 3] beat_samples = librosa.time_to_samples(test_beats, sr=sr) extracted_strength = test_audio[beat_samples] print(extracted_strength) # 预期输出:[1. 1.5 2. ]
如果输出和预期一致,就说明你的提取逻辑完全没问题。
备注:内容来源于stack exchange,提问作者Rahul Kumar
相关产品推荐
相关产品推荐

