CI COV License: MIT

SF2Lib - 一个 C++ 编写的 SoundFont (SF2) 合成器

这个库可以读取 SF2 SoundFont 文件,并实时渲染其中的音频样本。 它能够正确读取符合标准的 SF2 文件,并可以用来获取元数据,例如预设名称。 它还拥有一个音频渲染引擎,可以为来自(比如)MIDI 键盘的按键事件生成音频样本。 这个库目前被我的 SoundFonts 应用用于 SF2 文件解析,最近也作为 Apple 渲染功能的一个可选替代方案。

尽管库的大部分代码是通用的 C++17/23,但仍有一些部分依赖于具有 AudioToolbox 和 Accelerate 框架的 Apple 平台。 目标是成为一个简单的 SF2 文件读取库,以及一个能够胜任的 SF2 音频渲染器,其输出可以被馈送到任何类型的音频处理链中。 但是,可能需要付出一些努力才能将其从 Apple 生态系统中移除。

请注意,此软件包依赖于我 AUv3Support 软件包中的一些通用 DSP 头文件和音频类,该软件包被我的各种 AUv3 扩展所使用。

SF2 规范支持

目前,所有的 SF2 生成器和调制器都已根据 SoundFont 规范 v2 被支持和/或实现。 然而,这个库目前不包含合唱或混响效果。 在渲染时,如果使用了配置百分比的生成器设置,该库会将信号的百分比正确路由到合唱和混响总线/通道。

渲染 引擎renderInto 方法需要一个 Mixer 实例,该实例支持一个主要的“干声”总线和两个分别用于“合唱效果发送”和“混响效果发送”的总线。 这些总线由活动音色的样本填充,它们的音量由上面提到的 chorusEffectSendreverbEffectSend 参数控制。 然后,可以将总线 1 连接到合唱效果器,将总线 2 连接到混响效果器,然后将这些输出和此库的总线 0 连接到混音器,以生成最终输出。

代码

以下是 SF2Lib 中顶级文件夹的简要描述

单元测试

有大量的单元测试覆盖了代码库的很大一部分。 甚至有一些渲染测试,如果配置为这样做,将在结束时播放音频。 此选项位于 Package.swift 文件中的这一行 .define("PLAY_AUDIO", to: "0", .none)。 将 "0" 更改为 "1" 以启用所有测试的音频输出。

或者,具有渲染能力的单元测试具有一个 playAudio 属性,可以将其设置为 true 以播放来自测试的渲染输出。 请注意,测试结果不依赖于此设置,但启用此设置会增加运行测试所需的时间,因为播放录制的音频样本需要时间。

性能

当前代码尚未针对速度进行优化,但在包括移动设备在内的现代设备上仍然表现良好。 有两个测试(目前)提供了性能指标

正如它们的名称所暗示的那样,这些测试会运行一种特定的插值方法。 它们都生成 1 秒钟的 48K 采样率的音频,渲染 96 个同时发声的音符。 在优化的构建中,更昂贵的立方 4 阶插值测试需要约 0.27 秒才能完成,或约 1/4 的时间预算。 更快的线性插值降至约 0.25 秒。

通过遵循 FluidSynth 的方法,并且在大多数调制器和生成器不做更改的情况下一次渲染 64 个样本,可以获得额外的性能提升。 此外,可以检查待处理的 MIDI 事件列表以查看它是否为空,并选择支持矢量化渲染的路径。

Swift 集成

此软件包中的所有代码都是 C++/Objective C,但 Swift 软件包现在依赖于 Swift 5.9,以便访问现在可用的 Swift C++ 桥接。 这仅在 SF2Lib.hppSF2Lib.cpp 文件中使用,以声明一个与 Swift 兼容的接口到 C++ SF2::Render::Engine::Engine 类,这里命名为 SF2::Engine。 此接口创建并使用指向 SF2::Render::Engine::Engine 对象的指针,以便它可以隐藏来自 Swift 桥接框架的所有实现细节。

致谢

所有代码都是我自己多年来编写的,但我受益于其他项目的存在,尤其是 FluidSynth 及其在所有 SF2 方面拥有的丰富知识。 特别是,如果对 SF2 规范的含义有任何困惑,我依靠他们在代码中的解释。 也就是说,任何对 SF2 功能的错误陈述都是我自己的责任。