r8brain-free-src - 高质量、快速重采样器(C++实现)
简介
开源(MIT许可证)的高质量专业音频采样率转换器(SRC)/ 重采样器C++库。具有SRC功能,可进行上采样和下采样,支持任意采样率之间的转换,包括非整数采样率:它也可用于SACD/DSD采样率的转换,甚至可以超越这些范围。SRC例程以可移植、跨平台的C++代码实现,具有高度的优化性能。同时也适用于快速通用一维时间序列重采样/插值(使用宽松的滤波器参数)。
该库对象的结构使其可以在大型应用程序中频繁创建和销毁,对性能影响最小,这得益于其最"初始化昂贵"对象的高度可重用性:快速傅里叶变换和FIR滤波器对象。
SRC算法首先产生2倍过采样(相对于源采样率,或者目标采样率如果执行下采样)的信号,然后使用一组短(8到30个抽头,取决于所需精度)多项式插值的基于sinc函数的分数延迟滤波器进行插值。这使得该算法在最精确的SRC算法中属于最快的之一。更精确的替代方案只有整数因子SRC,但可能会更慢。
注:请在您的文档中以如下方式致谢本库的创建者:"采样率转换器由Voxengo的Aleksey Vaneev设计"。
要求
支持"double"浮点类型(53位尾数)的C++编译器和系统。本库中没有明确的"float"类型代码,因为实践表明,至少在这个库中,基于"float"的代码在现代处理器上运行速度明显较慢。除标准C库、Windows上的"windows.h"和macOS及Linux上的"pthread.h"外,本库没有其他依赖项。
使用信息
采样率转换器(重采样器)由r8b::CDSPResampler类表示,这是整个库的单一前端类。除此类外,您基本上不需要使用或理解任何其他类。还提供了几个具有不同精度级别的派生类(用于全分辨率16位和24位重采样)。
库的代码位于"r8b" C++命名空间中,有效地将其与所有其他代码隔离。代码是线程安全的。应为每个并发处理的音频通道或流创建一个单独的重采样器对象。
请注意,您需要编译"r8bbase.cpp"源文件,并将生成的目标文件包含到您的应用程序构建中。这个源文件包含了库使用的几个全局静态对象的定义。您可能还需要在项目中包含:Windows上的"Kernel32"库和macOS及Linux上的"pthread"库。
该库能够处理任何规模和响度的信号:它不仅限于"通常"的-1.0到1.0范围。
通过定义R8B_IPP
配置宏,可以启用Intel IPP后端用于FFT函数,而不是默认的Ooura FFT。IPP FFT平均使采样率转换速度提高23%。
#define R8B_IPP 1
如果较大的初始处理延迟和极小的采样时间误差不是问题,为了最高效率,您可以在r8bconf.h
文件开头或在编译时定义这些宏:
#define R8B_IPP 1
#define R8B_FASTTIMING 1
#define R8B_EXTFFT 1
如果您无法访问Intel IPP,那么您可以考虑启用PFFFT,其性能只比Intel IPP FFT略慢。有两个可用的宏:R8B_PFFFT
和R8B_PFFFT_DOUBLE
。第一个宏启用以单精度分辨率工作的PFFFT,从而将重采样器的总体精度限制为24位采样率转换(对于关键的专业音频应用,不建议使用R8B_PFFFT
宏,因为其峰值误差相当大)。第二个宏启用以双精度分辨率工作的PFFFT实现,利用SSE2、AVX和NEON内联函数,产生与Intel IPP和Ooura FFT实现相当的精度。
要使用PFFFT,请定义R8B_PFFFT
或R8B_PFFFT_DOUBLE
宏,编译并将提供的pffft.cpp
或pffft_double/pffft_double.c
文件包含到您的项目构建中。
#define R8B_PFFFT 1
或
#define R8B_PFFFT_DOUBLE 1
本库的代码采用Doxygen风格注释。要在本地生成文档,您可以从库的文件夹运行doxygen ./other/r8bdoxy.txt
命令。
初步测试表明,r8b::CDSPResampler24重采样器类在将1个声道的24位音频从44100采样率转换到96000采样率(2%过渡带)时,在基于Ryzen 3700X处理器的64位系统上可达到38*n_cores
百万次运算每秒(Intel IPP FFT为56*n_cores
)。这大约相当于在100%CPU负载下实时重采样860*n_cores
(1270*n_cores
)个音频流。转换到其他采样率时的性能可能会有很大差异。在比较此重采样器库与其他库的性能时,请确保竞争库也经过调整以产生完全线性相位响应,具有相似的阻带特性和相似的采样时间精度。
动态链接库
在Windows上,这个SRC库的功能也可以通过DLL文件以简化形式访问,需要支持SSE2的处理器(Win64版本包含AVX2自动分派代码)。DLL文件的Delphi Pascal接口单元文件可用。DLL和C LIB文件在项目主页的DLL文件夹中分发。在非Windows系统上,最好直接使用C++库。请注意,DLL是在启用Intel IPP的情况下编译的。
实时应用
此库的重采样器类被设计为异步处理器:它可能产生任意数量的输出样本,取决于输入样本数据长度和重采样参数。必须用输入样本数据持续馈送重采样器,直到产生足够的输出样本数据,多余的输出样本在馈送更多输入数据之前使用。这里的一个"缓解"因素是重采样器会自动移除初始处理延迟,并且在初始处理时刻之后,输出变得稳定,只有轻微的输出样本数据长度波动。
因此,虽然对于离线重采样可以使用"推"方法(如example.cpp
文件所示),但对于实时重采样应使用"拉"方法,即调用重采样过程直到输出缓冲区被填满。
注意事项
直接使用r8b::CDSPResampler类时,你可以选择低通(重建)滤波器的过渡带/陡度,以输入信号(或下采样时的输出信号)全谱带宽的百分比表示,以及所需的阻带衰减(以分贝为单位)。
过渡带被指定为输入信号(或下采样时的输出信号)的归一化频谱空间,介于低通滤波器的-3 dB点和奈奎斯特频率之间,范围从0.5%到45%。阻带衰减可以在49到218分贝范围内指定。过渡带和阻带衰减都会影响重采样器的整体性能和初始输出延迟。供参考,过渡频率范围跨越指定过渡带的175%,这意味着对于2%的过渡带,0.965*奈奎斯特以下的频率响应是线性的。
这个SRC库还实现了更快的"2的幂"重采样(例如2倍、4倍、8倍、16倍、3倍、32倍、34倍、3*8倍等上采样和下采样),如果重采样参数允许,会自动启用。
这个库已经在32位和64位Windows、macOS和CentOS Linux上测试了与GNU C++、Microsoft Visual C++、Clang和Intel C++编译器的兼容性。
大部分代码是"内联"的,无需编译多个源文件。内存占用相当适中。
对于高质量抖动,你可以考虑使用PRVHASH PRNG,它具有出色的心理声学性能。
致谢
r8brain-free-src捆绑了以下代码:
- FFT例程版权所有 (c) 1996-2001 Takuya OOURA。 主页
- PFFFT版权所有 (c) 2013 Julien Pommier。 主页
- PFFFT DOUBLE版权所有 (c) 2020 Hayati Ayguen, Dario Mambro。 主页
用户
以下项目使用了这个库:
- REAPER
- AUDIRVANA
- 荒野大镖客:救赎2
- 迷你钢琴精简版
- OpenMPT
- Boogex吉他放大器音频插件
- 语音朗读器
- Zynewave Podium
- Phonometrica
- Ripcord
- TensorVox
- Curvessor
- Hang Loose卷积器
- Wave Breaker
更新日志
版本6.5:
- 修复了getWholeStepping()函数,以允许对小于1.0的分数采样率进行GCD搜索。
- 将一些编译器不支持的浮点数0x1pN常量改为e表示法。
版本6.4:
- 改进了SSE检测宏。
版本6.3:
- 改进了findGCD()函数,以覆盖更广泛的采样率比。
- 添加了R8B_DSPBASECLASS宏,用于重新定义非缓存对象的基类。
版本6.2:
- 修复了最近引入的getInLenBeforeOutPos()函数对最小相位滤波器的错误计算。
- 修复了getInputRequiredForOutput()函数中的错误。
- 修复了整步插值中LatencyFrac值的长期错误。然而,这个错误之前并未造成实际问题(线性相位滤波器不存在,最小相位滤波器影响较小)。
版本6.1:
- 对"整步"插值进行了微优化,在某些转换中(如44100到96000)性能提升18%。
- 实现了getInLenBeforeOutPos()函数,这是getInLenBeforeOutStart()函数(现已成为遗留函数)的超快速灵活替代。还添加了getInputRequiredForOutput()辅助函数。
- 更新了整个代码库的注释部分,以匹配最新的Doxygen版本。
- 在DLL中重新引入了r8b_inlen()函数。
版本6.0:
- 为CDSPHBDownsampler添加了SSE和NEON实现,使2的幂次降采样性能提高5-16%。
- 进一步优化滤波器计算,速度提高15%。
- 将Windows互斥锁中的"SpinCount"提高到2000,以在滤波器缓存完全填满时更安全。
- 使最近使用的"静态"滤波器组弹出到列表顶部,适用于应用程序中使用多个"ReqAtten"值的情况。
版本5.9:
- 优化了滤波器计算(Kaiser窗函数),滤波结果变化可忽略不计。
- 优化了最小相位滤波器的群延迟计算。
- 将Windows互斥锁中的"SpinCount"减少到1000。
- 对整个代码库和注释进行了非必要的更改。
版本5.8:
- 重新排列了FFT宏,添加了R8B_PFFFT和R8B_PFFFT_DOUBLE冲突检查。
版本5.7:
- 移除了defined( __ARM_NEON )宏检测,以便在非ARM64平台上编译。
版本5.6:
- 为CDSPHBUpsampler添加了SSE和NEON实现,使2的幂次上采样性能提高15%。
- 为CDSPRealFFT::multiplyBlocksZP函数添加了SSE和NEON实现,性能提高2-3%。
- 添加了中间插值器的过渡带限制,以增加逻辑严密性(实际上不需要)。
- 在CDSPHBUpsampler构造函数中添加了aDoConsumeLatency参数,用于该类的"内联"DSP用途。
- 对整个代码库进行了各种小改动。
版本5.5:
- 加强了分数滤波器计算的位置逻辑,移除了多余的乘法。
- 从CDSPSincFilterGen类中移除了不必要的函数模板化。
- 在NEON可用性检测中添加了__ARM_NEON宏。
版本5.4:
- 为之前优化的内部循环添加了编译器专门化。"打乱"的SIMD插值代码在Apple M1上效率不高。Intel C++编译器对"整步"插值的向量化效果与手写SSE一样好。
- 重新组织了SIMD指令以略微提高性能。
- 更改了半带重采样器的内部缓冲区大小(性能提升1-2%)。
- 修复了PFFFT代码中的编译器警告。
- 在代码中添加了几个断言。
版本5.3:
- 优化了分数插值器的内部循环,添加了SSE2和NEON内联函数,导致性能显著提升(8-25%)。
- 优化了滤波器计算函数:将一些除以常数的操作改为乘法。
- 将M_PI宏重命名为R8B_PI,以避免宏冲突。
- 删除了冗余代码和宏。
版本5.2:
- 修改了
PFFFT
和PFFFT DOUBLE
条件预处理指令,以在aarch64
/arm64
上始终启用NEON(包括为Apple M1构建的代码)。
版本5.1:
- 将
CFixedBuffer
类的对齐方式改为64字节。这使PFFFT DOUBLE
实现的AVX性能提高了几个百分点。 - 删除了
pffft_double
文件夹中的冗余文件,将pffft_common.c
文件整合到pffft_double.c
文件中。
版本5.0:
- 从
r8bconf.h
文件中移除了一个过时已久的宏。 - 根据PFFFT DOUBLE作者的建议,更改了
pf_sse2_double.h
文件中的条件预处理指令,以允许在大多数编译器中使用SSE2内联函数。 - 修正了源文件中"License.txt"的错误命名为"LICENSE"。
版本4.10:
- 添加了
PFFFT DOUBLE
实现支持。现在可通过R8B_PFFFT_DOUBLE
定义宏使用。
版本4.9:
- 重新优化了半带和分数插值滤波器,采用更严格的频率响应线性度约束。这并未影响平均速度性能。
版本4.8:
- 为中间滤波器的过渡带添加了限制,以在任何重采样比下控制延迟。
版本4.7:
- 在
pffft.cpp
中添加了#ifndef _USE_MATH_DEFINES
。 - 将
#include "pffft.h"
移至CDSPRealFFT.h
。
版本4.6:
- 从
oneshot()
函数中移除了MaxInLen
参数。 - 略微减小了中间低通滤波器的过渡带,以获得更稳定的质量。
版本4.5:
- 修复了VS2017编译器警告。
版本4.4:
- 修复了Intel C++编译器的"Declaration hides a member"警告。
版本4.3:
- 添加了//$ 标记用于内部调试目的。
版本4.2:
- 将最大过渡带回调至45,最小衰减回调至49。
- 在
r8bfreesrc
基准工具中实现了Wave64和AIFF文件输入。该工具现在使用R8B_IPP 1
和R8B_EXTFFT 1
宏编译,以展示最高可达性能。
版本4.1:
- 更新了允许的ReqAtten范围为52-218,ReqTransBand为0.5-56。可以指定略微超出这些值的滤波器参数,但结果滤波器也会略微超出规格。
- 优化了静态滤波器组分配。
版本4.0:
- 对插值类进行了重大改进:现在不使用模板参数,所有必需参数在运行时计算。不使用静态滤波器组对象,而是在需要时创建,然后缓存。
- 实现了三分之一插值滤波器,但这并未明显提高重采样器的速度。
版本3.7:
- 在CDSPRealFFT::multiplyBlockZ()函数中使用ippsMul_64f_I(),在Intel IPP模式下略微提高了转换速度。
版本3.6:
- 为分配的缓冲区添加了内存对齐,当使用Intel IPP FFT时,性能提升了1.5%。
- 实现了PFFFT支持。
版本3.5:
- 略微提高了重采样速度。
- 更新了
r8bfreesrc
基准工具以支持RF64 WAV文件。
版本3.4:
- 为>=256的重采样比添加了更高效的半带滤波器。
版本3.3:
- 对CDSPBlockConvolver的某些用例进行了小修复,不影响重采样器。
- 将CDSPHBUpsampler和CDSPHBDownsampler的内部函数转换为静态函数,显著提高了高比率重采样性能。
版本3.2:
- 对延迟消耗机制进行了小修复。
版本3.1:
- 重新优化了分数延迟滤波器的窗函数。
版本3.0:
- 实现了getInLenBeforeOutStart()函数的新变体。
- 重新实现了oneshot()函数以支持
float
缓冲区类型。 - 大幅提高了高重采样比下的降采样性能。
- 实现了中间插值技术,显著提高了大多数重采样比下的上采样性能。
- 移除了ConvCount常量 - 现在重采样器支持几乎任何重采样比。
- 从重采样器构造函数中移除了UsePower2参数。
- 现在重采样器的process()函数始终返回内部缓冲区的指针,仅在不进行重采样时返回输入缓冲区。
- 现在可以使用重采样器的getMaxOutLen()函数获取重采样器在单次调用中可产生的最大输出长度。
- 为半带上采样器和降采样器添加了更高效的"三分之一"滤波器。
版本2.1:
- 优化了2X半带降采样器。
版本2.0:
- 优化了2的幂次方上采样。
版本1.9:
- 优化了半带下采样滤波器。
- 实现了整数步进重采样。
- 添加了
R8B_EXTFFT
配置选项。 - 修复了下采样时的初始子采样偏移。
版本1.8:
- 添加了
R8B_FASTTIMING
配置选项。
版本1.7:
- 提高了采样时间精度。
- 将CDSPResampler :: ConvCountMax增加到28,以支持更宽的重采样比率。
- 添加了
bench
工具。 - 由于计算不正确,移除了getInLenBeforeOutStart()函数。