☰
librosa 时间单位换算完全指南:frames、samples、time 与 blocks 的坐标转换体系
2026/9/25 2:08:51 网站建设 项目流程
  • 音频处理
  • 科研

【免费下载链接】librosa

Python library for audio and music analysis

项目地址:https://gitcode.com/gh_mirrors/li/librosa
点击查看免费下载

librosa 是 Python 生态中最常用的音频与音乐分析库之一,几乎所有音频分析管线都建立在"帧(frame)、采样点(sample)、秒(time)、块(block)"四套时间坐标之上。本文以 docs/api/core_timeunit.rst 中收录的 11 个时间单位换算 API 为核心,结合其底层实现 librosa/core/convert.py 与测试用例 tests/test_convert.py,系统讲解每一对换算关系的数学公式、参数语义、默认值以及在实际 beat 追踪、特征可视化、流式处理中的应用方式。读完本文,你将能熟练地在帧号、采样点索引、物理时间(秒)与流式块索引之间自由换算,并理解n_fft中心偏移对换算结果的影响。

为什么需要四套时间坐标系

音频信号在 librosa 中经历一条典型的数据链路:

  1. 采样点(samples):load/loadx读入的原始音频波形y,其索引单位是离散采样点,采样率sr表示每秒的采样点数(默认22050)。
  2. 帧(frames):STFT、chromagram、mel 谱等特征以"帧"为单位组织列,相邻帧之间相隔hop_length个采样点(默认512)。
  3. 时间(time):以秒为单位的物理时间戳,是用户最容易直观理解、也是可视化横轴最常用的坐标。
  4. 块(blocks):librosa.stream流式处理时按"块"读取音频,每块包含block_length帧。

由于beat_track返回的节拍位置、specshow绘制的横轴、stream产出的切片分别使用不同坐标系,librosa 在 librosa/core/convert.py 中集中实现了这四套坐标间的全部换算函数,并统一在 docs/api/core_timeunit.rst 页面(模块librosa.core)下公开。所有函数都同时接受标量与 NumPy 数组输入,返回值保持输入的形状与维度,可直接用于向量化计算。

帧与采样点:frames_to_samples/samples_to_frames

这是最基础的换算对,只依赖hop_length,与采样率无关。

帧 → 采样点:frames_to_samples

源码公式(librosa/core/convert.py):

times[i] = frames[i] * hop_length (+ offset)
  • frames:帧索引(标量或np.ndarray);
  • hop_length:相邻帧间隔的采样点数,默认512;
  • n_fft:可选参数。一旦给定,结果会加上n_fft // 2的偏移,用于抵消非中心 STFT 的窗效应(即第 0 帧实际对应n_fft // 2号采样点)。

典型用法是配合节拍追踪,把以帧为单位的节拍位置转成采样点(librosa/beat.py 内部即调用它实现units='samples'):

>>> y, sr = librosa.loadx('choice') >>> tempo, beats = librosa.beat.beat_track(y=y, sr=sr) >>> beat_samples = librosa.frames_to_samples(beats, sr=sr)

采样点 → 帧:samples_to_frames

源码公式(librosa/core/convert.py):

frames[i] = floor((samples[i] - offset) // hop_length)

n_fft给定的情况下偏移取- n_fft // 2,文档特别提示:这可能产生负的帧索引(当采样点落在首个 FFT 窗口中心之前时)。默认hop_length=512。官方 docstring 示例展示了每 256 个采样点取帧号的输出:

>>> librosa.samples_to_frames(np.arange(0, 22050, 256)) array([ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43])

两个方向均返回整数(dtype=int),且测试(tests/test_convert.py 中test_frames_to_samples/test_samples_to_frames)验证了:标量、一维、二维输入下输出形状与维度保持一致;n_fft给定时满足(samples - n_fft // 2) // hop_length == frames的往返一致性。

采样点与秒:samples_to_time/time_to_samples

这一对换算只依赖采样率sr(默认22050),公式最简单:

# samples_to_time(librosa/core/convert.py) times = samples / sr # time_to_samples samples = int(times * sr)
  • samples_to_time把采样点索引转换为秒,返回浮点数组,形状与输入一致;
  • time_to_samples把秒转换为采样点索引,返回dtype=int的数组。

官方示例直观展示了二者的互逆关系(以sr=22050为例):

>>> librosa.time_to_samples(np.arange(0, 1, 0.1), sr=22050) array([ 0, 2205, 4410, 6615, 8820, 11025, 13230, 15435, 17640, 19845]) >>> librosa.samples_to_time(np.arange(0, 22050, 512), sr=22050) array([ 0. , 0.023, 0.046, 0.07 , 0.093, 0.116, 0.139, 0.163, 0.186, 0.209, 0.232, 0.255, 0.279, 0.302, 0.325, 0.348, 0.372, 0.395, 0.418, 0.441, 0.464, 0.488, 0.511, 0.534, 0.557, 0.58 , 0.604, 0.627, 0.65 , 0.673, 0.697, 0.72 , 0.743, 0.766, 0.789, 0.813, 0.836, 0.859, 0.882, 0.906, 0.929, 0.952, 0.975, 0.998])

对应测试test_time_to_samples/test_samples_to_time在sr=22050与sr=44100下分别验证了time_to_samples([0,1,2]) == [0, sr, 2*sr]与samples_to_time([0, sr, 2*sr]) == [0,1,2]的往返关系。

帧与秒:frames_to_time/time_to_frames

这两者不是独立实现,而是"组合调用链"的典型代表——理解它们能帮你看清 librosa 的代码组织哲学。

frames_to_time(librosa/core/convert.py)先调frames_to_samples再调samples_to_time,等效公式:

times[i] = frames[i] * hop_length / sr

参数:sr(默认22050)、hop_length(默认512)、n_fft(可选,产生n_fft // 2偏移)。它是最常用的可视化辅助函数,例如 librosa/feature/utils.py 中绘制节拍同步 chroma 的示例就用它生成横轴坐标:

>>> y, sr = librosa.loadx('sweetwaltz', duration=10) >>> chroma = librosa.feature.chroma_cqt(y=y, sr=sr) >>> tempo, beats = librosa.beat.beat_track(y=y, sr=sr, hop_length=512) >>> beats = librosa.util.fix_frames(beats, x_min=0) >>> chroma_sync = librosa.util.sync(chroma, beats) >>> beat_times = librosa.frames_to_time(beats, sr=sr, hop_length=512) >>> librosa.display.specshow(chroma_sync, y_axis='chroma', x_axis='time', ... x_coords=beat_times)

time_to_frames(librosa/core/convert.py)则反向组合time_to_samples→samples_to_frames,等效公式:

frames[i] = floor(times[i] * sr / hop_length)

官方示例:每 100ms 取一次帧号(sr=22050, hop_length=512):

>>> librosa.time_to_frames(np.arange(0, 1, 0.1), sr=22050, hop_length=512) array([ 0, 4, 8, 12, 17, 21, 25, 30, 34, 38])

测试test_frames_to_time/test_time_to_frames在多种sr、hop_length、n_fft组合下验证了"误差控制在一个帧以内"的精度保证。

流式处理的块坐标:blocks_to_frames/blocks_to_samples/blocks_to_time

librosa.stream以"块"为单位处理长音频,三个blocks_to_*函数把块索引映射到另外三种坐标,统一接受block_length(每块包含的帧数)参数,其中后两者额外需要hop_length(blocks_to_time还需sr)。

  • blocks_to_frames:frames = block_length * blocks,线性映射;
  • blocks_to_samples:先blocks_to_frames再frames_to_samples,即samples = blocks * hop_length * block_length;
  • blocks_to_time:再经samples_to_time得到秒数。

关键语义:blocks_to_samples与blocks_to_time返回的是每块首个样本的索引/时间,并非帧中心位置(docstring 中明确 "are not frame-centered")。这在拼接流式处理结果、计算块边界时需要格外注意。

官方示例统一演示了与stream的配合:

>>> filename = librosa.ex('brahms') >>> sr = librosa.get_samplerate(filename) >>> stream = librosa.stream(filename, block_length=16, ... frame_length=2048, hop_length=512) >>> for n, y in enumerate(stream): ... n_frame = librosa.blocks_to_frames(n, block_length=16) ... n_sample = librosa.blocks_to_samples(n, block_length=16, hop_length=512) ... n_time = librosa.blocks_to_time(n, block_length=16, ... hop_length=512, sr=sr)

这里librosa.ex('brahms')与librosa.get_samplerate分别来自 librosa/core/audio.py 的示例音频与采样率查询接口。测试 tests/test_convert.py 对blocks(标量与[10, 20]列表)、block_length(1/4/8)、hop_length(1/512)、sr(22050/44100)做了全组合参数化验证,并确认输出保持输入维度且dtype为整数。

特征矩阵一键对齐:samples_like/times_like

specshow、chromagram、mel 谱等特征矩阵的"时间轴长度"就是列数(帧数),而绘制时往往需要横轴坐标。times_like/samples_like就是为了解决"不必手动数帧数"而设计的便捷函数。

  • times_like(X, sr=22050, hop_length=512, n_fft=None, axis=-1):返回与X时间轴对齐的秒数组;
  • samples_like(X, hop_length=512, n_fft=None, axis=-1):返回与X时间轴对齐的采样点索引数组。

两者输入X有两种形态(librosa/core/convert.py):

  1. 特征矩阵:X为np.ndarray(如 STFT 结果D),此时取X.shape[axis]作为帧数,axis默认-1(最后一维为时间轴);
  2. 标量:X直接表示帧数,内部等价于np.arange(X)。

底层实现都是"生成帧号序列 →frames_to_samples(→samples_to_time)",与前面介绍的函数完全同源:

>>> y, sr = librosa.loadx('trumpet') >>> D = librosa.stft(y) >>> times = librosa.times_like(D, sr=sr) # 特征矩阵输入 >>> samples = librosa.samples_like(D) # 采样点索引输入 >>> n_frames = 2647 >>> times = librosa.times_like(n_frames, sr=sr) # 标量输入

测试 tests/test_convert.py 中test_samples_like/test_times_like对形状(3,4,5)的矩阵遍历axis ∈ {0,1,2,-1}全部验证通过;test_*_scalar则验证了标量X=7时等价于np.arange(7) * hop_length(再除以sr)。这正是specshow(..., x_axis='time', x_coords=times)与waveshow内部坐标映射所依赖的机制。

实战场景:把节拍位置换算成秒

最典型的端到端场景是librosa.beat.beat_track的输出单位切换。在 librosa/beat.py 中可以看到,节拍追踪器内部以帧为单位计算beats,随后依据units参数在返回前统一换算:

  • units='frames':原样返回帧索引;
  • units='samples':调用core.frames_to_samples(beats, hop_length=hop_length);
  • units='time':调用core.frames_to_time(beats, hop_length=hop_length, sr=sr)。
>>> y, sr = librosa.loadx('choice') >>> tempo, beats = librosa.beat.beat_track(y=y, sr=sr) # beats 为帧索引 >>> beat_times = librosa.frames_to_time(beats, sr=sr) # 转为秒

这也解释了为什么这三个换算函数会被beat、onset、segment、display、feature等多个模块共同依赖——它们是特征时间轴与物理时间之间的唯一桥梁。

数值约定与注意事项汇总

函数公式关键默认值返回类型
frames_to_samplesframes * hop_length (+ n_fft//2)hop_length=512int
samples_to_framesfloor((samples − offset) // hop_length)hop_length=512int
samples_to_timesamples / srsr=22050float
time_to_samplestimes * srsr=22050int
frames_to_timeframes * hop_length / srsr=22050, hop_length=512float
time_to_framesfloor(times * sr / hop_length)sr=22050, hop_length=512int
blocks_to_framesblocks * block_length必传block_lengthint
blocks_to_samplesblocks * block_length * hop_length必传block_length, hop_lengthint
blocks_to_time上式再除以sr必传block_length, hop_length, srfloat
samples_like由矩阵形状/标量帧数生成hop_length=512, axis=-1int
times_likesamples_like结果除以srsr=22050, hop_length=512, axis=-1float

使用时的五个要点:

  1. 所有函数均接受标量与数组,输出保持输入形状(0-d/1-d/2-d均被测试覆盖),可放心向量化;
  2. n_fft是可选项:只有使用非中心 STFT 或需要抵消窗偏移时才传入;传入后samples_to_frames/time_to_frames可能返回负帧索引,这是文档明示的预期行为,不是 bug;
  3. hop_length与sr必须与上游特征计算时保持一致,否则换算结果会整体偏移;
  4. blocks_to_samples/blocks_to_time返回块首样本位置,不是帧中心,拼接流数据时要自行对齐;
  5. 负数输入同样按公式运算(如time_to_frames对负时间返回负帧号),边界判断应放在调用方。

若需进一步了解相邻模块,可继续阅读 docs/api/core_frequnit.rst(频率单位换算)与 docs/api/core_audio.rst(音频加载与流式处理),完整函数清单见 docs/api/index.rst。

  • 音频处理
  • 科研

【免费下载链接】librosa

Python library for audio and music analysis

项目地址:https://gitcode.com/gh_mirrors/li/librosa
点击查看免费下载

相关推荐

上一篇:3种ESP32实战开发方案:从智能监测到混合通信架构设计
下一篇:linux-inject vs LD_PRELOAD:两种Linux注入技术的终极对比分析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询