FluidSynth
更新于 2026-10-28 10:13:42
一句话定位
FluidSynth 是一个跨平台的实时软件合成器,严格按 SoundFont 2 规范实现:你给它一个 MIDI 事件流 + 一个 SoundFont 音色库,它吐出采样率准确的音频。可以理解成「一块软 MIDI 音源卡」——没有图形界面,只有命令行、C API 和一堆音频/ MIDI 驱动后端。
LGPL-2.1,纯 C,2.5k★,最新 v2.6.1(2026-09-19)。它是 Linux 世界 MIDI 播放的事实标准,也是无数打谱软件、播放器、游戏引擎背后那个「发声的东西」。
它到底解决什么问题
MIDI 文件里没有声音,只有「按了哪个键、多用力、什么时候松开」。要听到声音,必须有人把指令翻译成采样:这就是音源(synthesizer)+ 音色库(SoundFont)干的事。
- SoundFont(.sf2 / .sf3):一种把采样波形、循环点、包络、滤波器、键位映射打包在一起的标准格式,一个文件里就有整套 GM 音色(128 种乐器 + 鼓组)。
.sf3是 Ogg Vorbis 压缩版,体积小很多,FluidSynth 原生支持。 - FluidSynth 的角色:读 SF2 → 按 MIDI 通道/音色号分配到声部 → 做采样插值、包络、滤波、混响、合唱 → 输出 PCM 给 ALSA / PulseAudio / JACK / CoreAudio / WASAPI / Oboe 等后端。
所以典型链路是:MIDI 文件 → FluidSynth(+ SF2)→ WAV/实时音频。
三种用法,从简单到硬核
1. 当播放器:接上 MIDI 键盘就能弹
官方 wiki 给的最省事写法(Linux 桌面,PulseAudio 输出 + ALSA 音序器输入,自动连上已插的 MIDI 设备):
fluidsynth -a pulseaudio -m alsa_seq -o midi.autoconnect=1 -g 1.0 piano.sf2
JACK 用户:
fluidsynth -a jack -j -m jack /path/to/soundfont.sf2
macOS:
fluidsynth -a coreaudio -m coremidi /path/to/soundfont.sf2
启动后进的是一个内置 shell,可以直接敲 noteon 0 60 100、load other.sf2、inst 0 40 这类命令调试音色,不用写代码。
2. 当渲染器:批量把 MIDI 转成 WAV
这是自动化场景最有价值的用法。-F 走非实时快速渲染,多长的曲子都是「算多快就多快」,不按 1:1 时间播放:
fluidsynth -F out.wav -r 44100 -g 0.5 synth.sf2 song.mid
-T 指定渲染输出格式(-T raw 就是裸 PCM),配合 -F- 还能直接写 stdout,管道给别的程序:
fluidsynth -T raw -F- -q synth.sf2 song.mid | aplay -f cd
(官方注明这个 stdout 玩法需要 ≥ 2.1.0。)
低配机器担心爆音,就砍混响、合唱、采样率,并加大缓冲:
fluidsynth -C0 -R0 -r22050 -z8192 -a alsa -o audio.alsa.device=plughw:0 -o synth.polyphony=64
-C0 -R0 关合唱和混响,-r 降采样率,-z 加音频缓冲,synth.polyphony 降同时发声数——四条一起压 CPU 和内存。
3. 当库:嵌进自己的程序
C API 的心智模型非常简单,六步就能出声:
fluid_settings_t *settings = new_fluid_settings();
fluid_settings_setnum(settings, "synth.sample-rate", 44100.0);
fluid_synth_t *synth = new_fluid_synth(settings);
fluid_synth_sfload(synth, "piano.sf2", 1); /* 1 = 立即重设 MIDI 映射 */
fluid_synth_program_change(synth, 0, 0); /* 通道 0 选钢琴 */
fluid_synth_noteon(synth, 0, 60, 100); /* 中音 C,力度 100 */
/* ……接上 audio driver 或手动 fluid_synth_write_* 拉数据…… */
delete_fluid_synth(synth);
delete_fluid_settings(settings);
官方仓库 doc/examples/ 下有一整套可编译示例:fluidsynth_simple.c、fluidsynth_fx.c(挂效果器)、fluidsynth_metronome.c、fluidsynth_sfload_mem.c(音色库从内存加载,适合打包进 App)、fluidsynth_enumsettings.c(枚举所有可调参数)——比读文档快。
没有声卡也能用:不用 audio driver,直接调 fluid_synth_write_s16() 手动拉帧,塞进自己的音频回调(游戏、Unity、安卓 Oboe、离线渲染管线都是这么干的)。
谁在用(官方清单里的硬证据)
这不是个玩具。官方 wiki 的「Applications using FluidSynth」列了一长串下游:
| 类型 | 例子 |
|---|---|
| 打谱 / 音乐教育 | MuseScore、Denemo、ScoreDate、PianoBooster、TuxGuitar |
| 播放器 | VLC、Audacious、Drumstick MIDI Player、QSynth(Qt 前端) |
| 音频工作站 | LMMS、Ardour(自带 a-fluidsynth LV2 插件) |
| 游戏 / 模拟器 | ScummVM、DOSBox Staging、Simutrans、mt32-pi(树莓派裸机 MIDI 合成) |
| 语言 / 框架绑定 | pygame(Linux 下播 MIDI)、Unity 的 Maestro 插件、juicysfplugin(macOS AU/VST) |
也就是说:你在 Linux 上听到的绝大多数 MIDI 声音、老游戏里那段配乐、打谱软件点播放时响的那一下,背后大概率就是它。
坑与注意
- 音色库才是音质的天花板:FluidSynth 只负责算,好不好听取决于 SF2。免费的 GeneralUser GS(约 30MB)够用,FluidR3_GM(约 140MB)更饱满,专业音色库动辄几个 GB。另外 SF2 里常含第三方采样,商用前要单独确认音色库的授权,这跟 FluidSynth 的 LGPL 是两件事。
- CPU 是单线程渲染的:复音数拉高(大谱面、踏板全踩)容易爆音/掉帧,先降
synth.polyphony再考虑别的。 - Linux 上驱动选错就没声:
-a支持 alsa / pulseaudio / jack / pipewire(多数发行版走 pulse 或 jack 兼容层),-m支持 alsa_seq / alsa_raw / jack / coremidi / winmidi。插了键盘但没反应,优先查-m和midi.autoconnect。 - 延迟想低就走 JACK:PulseAudio 那条路胜在「开箱能用」,实时演奏还是 JACK/PipeWire-JACK 更稳。
- LGPL 的边界:动态链接或作为独立进程调用基本没有额外义务;静态链接则要提供可重新链接的目标文件/源码。官方专门写了 Licensing FAQ,商业闭源项目动手前先读。
- 不要指望它做效果链:它有混响、合唱、IIR 滤波和 LADSPA 接口,但不是 DAW。要压缩、EQ、母带,交给下游。
二开建议
- 编译:CMake(
BuildingWithCMake.md在 wiki 里)。依赖很轻,关掉不需要的驱动后端能显著减少体积——做嵌入式/安卓时这步很关键。 - 安卓 / iOS:仓库里带
doc/android(含 assetloader,可直接从 APK assets 里读 SF2)和官方 iOS 预编译 zip(v2.6.1 的 Release 资产里就有fluidsynth-v2.6.1-iOS.zip)。 - 只想要「MIDI → WAV」:别写 C,直接调可执行文件 +
-F,比自己链库省事,也天然隔离了 LGPL 和崩溃风险。 - 只要一个插件:社区已经做了 CLAP(fluidsynth.clap)、VST3(FluidSynthPlugin)、LV2(Ardour 的 a-fluidsynth)、AU/VST(juicysfplugin),先看现成的再决定要不要自己撸。
- 参数别硬编码:所有可调项都能用
-o key=value或fluid_settings_set*改,配置文件也支持;打包时用-f指定自己的 config,用户改不坏。
一句话总结
FluidSynth 是「MIDI 世界的声音出口」:一个 LGPL 的纯 C 软音源,命令行能放能转、C API 能嵌、后端覆盖几乎所有平台。它的价值不在界面,而在于稳定、无依赖、可脚本化——想把 MIDI 批量变成音频、或者给自己的程序加个 SF2 音源,它几乎是最省事的选择。音质由 SoundFont 决定,CPU 单线程是唯一硬约束。