音频响度标准化
分析并归一化到广播 / 流媒体响度标准(-14 / -16 / -23 LUFS)
LUFS 标准化/直播/短视频音量统一
分析并归一化到广播 / 流媒体响度标准(-14 / -16 / -23 LUFS)
LUFS(Loudness Units Full Scale):感知响度单位(ITU-R BS.1770 / EBU R128 标准)。基于人耳听觉曲线加权,比单纯峰值 / RMS 更准确反映 "听感响度"。
流媒体标准:Spotify -14 LUFS / YouTube -14 LUFS / Apple Music -16 LUFS / Amazon -14 LUFS / Tidal -14 LUFS。上传超响内容会被自动降低。
广播标准:欧洲 EBU R128 = -23 LUFS / 美国 ATSC A/85 = -24 LUFS / 日本 ARIB TR-B32 = -24 LUFS。
本工具实现:简化的 K-weighting + Integrated Loudness 估算。生产级精确需使用 ITU 完整实现(本工具结果与专业仪表通常误差 ±0.5 LUFS)。
了解工具定位 · 使用场景 · 对比优势
播客制作人录制了 3 位嘉宾的远程对谈,每轨音量差异可达 6-8 dB。手动逐段调电平耗时且容易失真。使用本工具将所有轨道统一归一化到 -23 LUFS(ITU-R BS.1770 推荐标准),单次批量处理,输出文件间音量差 ≤ 0.5 LU,无需二次微调即可直接发布。
内容创作者需要将同一段口播视频同时发布到抖音(目标 -14 LUFS)和 B 站(目标 -23 LUFS)。本工具支持分别设定目标响度值,一次上传输出两份不同标准的文件。避免了在剪辑软件里来回切换导出配置的麻烦,也防止因响度差异导致平台二次压缩影响音质。
直播运营团队每月积累 200+ 小时回放素材,因主播声场位置变动、连麦嘉宾设备不同,各段视频响度浮动达 10 dB。本工具批量扫描文件夹内所有 MP4 文件,自动检测并归一化至目标 LUFS 值(如 -16 LUFS),输出文件间音量差控制在 1 LU 以内,可直接用于后期剪辑或存档。
有声书录制周期长达数月,不同章节可能由不同录音棚完成,成品响度差异明显。使用本工具对全部章节统一归一化到 -20 LUFS(AES 推荐标准),保证听众在连续收听时音量平稳,避免因响度跳变导致用户体验中断或投诉。
广告代理商每天需交付 50+ 条 30 秒电台广告,但客户提供的原始素材响度参差不齐(-18 到 -12 LUFS)。本工具一键将所有素材归一化至 -14 LUFS(广播行业通用标准),输出文件符合电台播出系统的响度门限要求,避免因响度超标被拒稿或罚款。
| 维度 | 本工具 | 竞品 A(Adobe Audition) | 传统方法(手动调整) |
|---|---|---|---|
| 数据隐私 | 纯浏览器端处理,文件不上传服务器 | 需安装客户端,文件本地处理 | 文件本地处理,无网络传输风险 |
| 处理速度 | 1-5 秒(取决于文件大小) | 5-30 秒(含软件启动与渲染时间) | 10-60 分钟(依赖人工听测与手动调整) |
| 操作门槛 | 拖拽上传,一键处理 | 需安装软件,熟悉多轨/效果器操作 | 需专业音频知识,手动调整增益/压缩器 |
| 离线可用 | 依赖网络(加载 WASM 引擎) | 完全离线 | 完全离线 |
| 收费 | 免费 | 按月/年订阅(Creative Cloud) | 免费(人工成本) |
| 批量处理 | 单次处理一个文件 | 支持批量处理与预设 | 逐一手动操作 |
| 输出标准 | ITU-R BS.1770-4(LUFS) | 支持多种响度标准(LUFS/EBU R128/ATSC A/85) | 依赖个人经验,无统一标准 |
上手步骤 · 输入输出 · 避坑提示
| 输入 | 输出 | 说明 |
|---|---|---|
| 输入音频文件(如 48kHz/16bit WAV,平均响度 -18 LUFS) | 输出文件:归一化至 -14 LUFS(目标响度),峰值 -1 dBTP | 典型场景:短视频平台统一音量标准 |
| 输入音频文件(如 44.1kHz/16bit MP3,平均响度 -23 LUFS) | 输出文件:归一化至 -14 LUFS,峰值 -1 dBTP | 典型场景:播客或直播录音音量提升 |
| 输入音频文件(如 96kHz/24bit FLAC,平均响度 -8 LUFS) | 输出文件:归一化至 -14 LUFS,峰值 -1 dBTP | 边界 case:原始响度已高于目标,会降低音量 |
| 输入音频文件(如 8kHz/8bit 电话录音,平均响度 -30 LUFS) | 输出文件:归一化至 -14 LUFS,峰值 -1 dBTP | 边界 case:极低采样率和位深,增益幅度大 |
| 输入音频文件(如 192kHz/32bit float,平均响度 -14 LUFS) | 输出文件:归一化至 -14 LUFS,峰值 -1 dBTP | 边界 case:已达标,输出基本无变化 |
| 输入音频文件(如 48kHz/16bit WAV,平均响度 -14 LUFS,但峰值 -0.5 dBTP) | 输出文件:归一化至 -14 LUFS,峰值 -1 dBTP(可能削波或压缩) | 易错 case:峰值已接近 0 dB,归一化后可能失真 |
| 输入音频文件(如 48kHz/16bit WAV,平均响度 -14 LUFS,但采样率 48kHz) | 输出文件:归一化至 -14 LUFS,峰值 -1 dBTP | 易错 case:用户误以为需要手动匹配采样率 |
目标响度:0 LUFS目标响度:-14 LUFS(流媒体标准)或 -23 LUFS(广电标准)LUFS 是负值刻度,0 LUFS 是数字满量程极限,任何实际节目峰值都会超过 0 导致削波失真。常见标准在 -14 到 -23 之间。
上传一个 .jpg 图片文件或一个静音视频 .mp4上传包含音频流的 .mp3、.wav、.flac 或带音轨的 .mp4/.mov工具基于 FFmpeg 处理音频流。无音频流的文件会报错或输出空文件,且不会自动跳过。
期望输出文件音量听起来和原文件一样大,但实际音量变小了理解峰值归一化(调最大振幅到 0dBFS)≠ 响度归一化(调平均能量到目标 LUFS)峰值归一化不改变平均听感响度,只改变瞬时峰值;响度归一化会整体提升或降低音量,使不同片段听感一致。
对一个 0.3 秒的枪声音效文件做 -14 LUFS 标准化对短音效使用“短时响度”(Short-term LUFS)或不做标准化LUFS 标准(ITU-R BS.1770-4)针对长节目设计,短片段测量不稳定。1 秒以下片段标准化后可能音量剧烈变化。
目标响度 -14 LUFS,不做 True Peak 限制目标响度 -14 LUFS,同时限制 True Peak ≤ -1 dBTP(流媒体标准)仅做 LUFS 标准化不限制真实峰值,输出文件在解码时可能因插值重建产生超出 0dBFS 的采样点,导致播放器削波。
期望输出文件比原文件更响、更炸耳理解响度归一化是“统一音量”,不是“压限提增益”如果原文件已经比目标 LUFS 更响(如 -8 LUFS),归一化后音量反而会降低。这是为了统一播放标准,不是音量竞赛。
5.1 环绕声文件直接做响度归一化,结果只有左声道有声音确认工具支持多声道 LUFS 测量(按 ITU-R BS.1770-4 各声道加权),或先下混为立体声再处理部分简易实现只处理前两个声道,导致环绕声文件丢失中置、低音等声道。正确实现应按标准对各声道加权求和。
公式推导 · 流程图解 · 依据出处
G = -18 × LUFS(original) + 0
G — 增益量(dB),用于调整音频LUFS(original) — 原始音频的集成响度值一段直播音频原始响度为 -23 LUFS。目标响度为 -18 LUFS(ITU-R BS.1770-4 标准)。增益量 G = -18 - (-23) = +5 dB。将音频整体提升 5 dB 后,输出响度即为 -18 LUFS。
基于 ITU-R BS.1770-4 标准,适用于立体声/单声道音频的 LUFS 归一化。不适用于多声道环绕声(5.1/7.1)或已限幅/削波的音频,因峰值可能超出 0 dBFS 导致失真。
3 种主流语言 · 复制即用
import subprocess
import json
# 使用 ffmpeg 将音频归一化到 -14 LUFS (ITU-R BS.1770-4)
input_file = "input.mp3"
output_file = "output.mp3"
# 第一步:分析当前响度
analysis = subprocess.run(
["ffmpeg", "-i", input_file, "-af", "loudnorm=I=-14:print_format=json",
"-f", "null", "-"],
capture_output=True, text=True
)
# 从 stderr 提取 JSON 分析结果(ffmpeg 将分析数据输出到 stderr)
stderr_lines = analysis.stderr.split('\n')
json_start = next(i for i, l in enumerate(stderr_lines) if l.strip().startswith('{'))
params = json.loads('\n'.join(stderr_lines[json_start:]))
# 第二步:应用测量参数进行精确归一化
subprocess.run([
"ffmpeg", "-i", input_file,
"-af", f"loudnorm=I=-14:LRA=7:TP=-1.5:"
f"measured_I={params['input_i']}:"
f"measured_LRA={params['input_lra']}:"
f"measured_TP={params['input_tp']}:"
f"measured_thresh={params['input_thresh']}:"
f"offset={params['target_offset']}",
output_file
], check=True)
print(f"归一化完成: {output_file}")
package main
import (
"encoding/json"
"fmt"
"os/exec"
"strings"
)
func main() {
input := "input.wav"
output := "output.wav"
// 第一遍:分析原始响度
cmd := exec.Command("ffmpeg", "-i", input,
"-af", "loudnorm=I=-14:print_format=json",
"-f", "null", "-")
out, _ := cmd.CombinedOutput()
// 从输出中提取 JSON 块
outStr := string(out)
start := strings.Index(outStr, "{")
end := strings.LastIndex(outStr, "}") + 1
if start == -1 || end == 0 {
panic("无法解析响度分析结果")
}
var params struct {
InputI float64 `json:"input_i"`
InputLRA float64 `json:"input_lra"`
InputTP float64 `json:"input_tp"`
InputThresh float64 `json:"input_thresh"`
TargetOffset float64 `json:"target_offset"`
}
json.Unmarshal([]byte(outStr[start:end]), ¶ms)
// 第二遍:应用精确归一化
filter := fmt.Sprintf(
"loudnorm=I=-14:LRA=7:TP=-1.5:"+
"measured_I=%.2f:measured_LRA=%.2f:"+
"measured_TP=%.2f:measured_thresh=%.2f:"+
"offset=%.2f",
params.InputI, params.InputLRA,
params.InputTP, params.InputThresh,
params.TargetOffset)
cmd = exec.Command("ffmpeg", "-i", input, "-af", filter, output)
if err := cmd.Run(); err != nil {
panic(err)
}
fmt.Println("归一化完成:", output)
}
// 浏览器端:使用 Web Audio API 分析并调整响度(简化版 LUFS 近似)
// 注意:完整 LUFS 需要多通道分析,此处展示单通道 RMS 能量归一化
async function normalizeLoudness(audioBuffer) {
const ctx = new OfflineAudioContext(
audioBuffer.numberOfChannels,
audioBuffer.length,
audioBuffer.sampleRate
);
// 复制音频数据到离线上下文
const source = ctx.createBufferSource();
source.buffer = audioBuffer;
source.connect(ctx.destination);
source.start();
// 渲染并获取原始数据
const rendered = await ctx.startRendering();
const channelData = rendered.getChannelData(0);
// 计算 RMS(均方根)能量
let sumSquares = 0;
for (let i = 0; i < channelData.length; i++) {
sumSquares += channelData[i] ** 2;
}
const rms = Math.sqrt(sumSquares / channelData.length);
// 目标 RMS 对应 -14 LUFS 的近似值(0 dBFS = 0 LUFS 时)
const targetRMS = 0.2; // 约 -14 dBFS
const gain = targetRMS / (rms || 1);
// 应用增益
const normalized = new Float32Array(channelData.length);
for (let i = 0; i < channelData.length; i++) {
normalized[i] = Math.max(-1, Math.min(1, channelData[i] * gain));
}
return normalized;
}
// 使用示例(假设已从 <audio> 或 fetch 获得 AudioBuffer)
// const audioCtx = new AudioContext();
// const response = await fetch('audio.mp3');
// const arrayBuffer = await response.arrayBuffer();
// const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);
// const normalized = await normalizeLoudness(audioBuffer);
// console.log('归一化完成,样本数:', normalized.length);
9 个高频疑问
「杂项」下的其他工具