openverse-sfx

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

openverse-sfx: Free Licensed Sound Design for Video, Verified by Measurement

openverse-sfx:免费授权视频声音设计,以测量结果验证

You cannot hear. Every decision in this skill is made by measurement (
librosa
,
ffmpeg ebur128
, waveform plots) and verified on the exported file - never by feel, and never tell the user it sounds good. Hand them a short list of timestamps to check with headphones instead.
All audio comes from Openverse (
https://api.openverse.org
): 5.2M free audio files, no API key, $0. Never synthesize music or sound effects in code - no sine-wave beeps, no noise bursts. Use real licensed recordings only.

你无法直接听到声音。本 skill 中的每项决策都基于测量结果(
librosa
、
ffmpeg ebur128
、波形图),并在导出的文件上进行验证——绝不凭感觉判断,也绝不要告诉用户它听起来不错。改为向用户提供一组简短的时间戳,供他们使用耳机检查。
所有音频均来自 Openverse(
https://api.openverse.org
):包含 520 万个免费音频文件,无需 API key,费用为 $0。绝不要在代码中合成音乐或音效——不要使用正弦波蜂鸣声或噪声爆发。只使用真实且已授权的录音。

Critical Rules

关键规则

  1. License filter is mandatory. Only use Openverse results with
    license=cc0,by,pdm
    and
    source=freesound,jamendo
    .
    scripts/sfx_search.py
    enforces this - do not bypass it.
  2. One search per kind of sound. Anonymous Openverse use is limited to ~200 searches/day. Search once per sound kind (
    "whoosh"
    ,
    "ui pop"
    ,
    "upbeat loop"
    ) and pick from the shortlist. Do not re-search with rephrased queries.
  3. credits.txt
    is not optional.
    CC BY audio is only legal to use with credit. Every downloaded file's
    attribution
    field goes into
    credits.txt
    verbatim.
    scripts/sfx_fetch.py
    does this automatically. CC0/PDM need nothing, but log them anyway.
  4. Prerequisites first. If missing, install before starting:
    ffmpeg
    , and
    pip install librosa matplotlib numpy scipy
    .
  5. Measure the exported MP4, never the pre-export WAV. AAC compression and mono phone playback change the result; only the shipped file counts.

  1. 必须使用许可证过滤器。 仅使用
    license=cc0,by,pdm
    且
    source=freesound,jamendo
    的 Openverse 搜索结果。
    scripts/sfx_search.py
    会强制执行这些限制——不要绕过它。
  2. 每种声音只搜索一次。 Openverse 匿名使用每天最多约 200 次搜索。每种声音类型只搜索一次(
    "whoosh"
    、
    "ui pop"
    、
    "upbeat loop"
    ),然后从候选列表中选择。不要使用改写后的查询重复搜索。
  3. credits.txt
    不是可选项。
    CC BY 音频只有在提供署名的情况下才能合法使用。每个下载文件的
    attribution
    字段都应原样写入
    credits.txt
    。
    scripts/sfx_fetch.py
    会自动完成此操作。CC0/PDM 无需署名,但仍要记录。
  4. 先检查前置条件。 如果缺少依赖,请先安装再开始:安装
    ffmpeg
    ,并执行
    pip install librosa matplotlib numpy scipy
    。
  5. 测量导出的 MP4,绝不测量导出前的 WAV。 AAC 压缩和手机以单声道播放都会改变结果;只有最终交付的文件才有效。

Workflow

工作流

Step 1 - Music

第 1 步 - 音乐

Use a track the user gave you, or search Openverse for one (
python3 scripts/sfx_search.py --query "upbeat loop" --min-ms 15000
). Note the source and license. Download it with
scripts/sfx_fetch.py
into
sfx/
so its attribution lands in
credits.txt
.
使用用户提供的音轨,或在 Openverse 中搜索一首(
python3 scripts/sfx_search.py --query "upbeat loop" --min-ms 15000
)。记录来源和许可证。使用
scripts/sfx_fetch.py
将其下载到
sfx/
,这样其 attribution 就会写入
credits.txt
。

Step 2 - Beat Grid

第 2 步 - 节拍网格

Run
python3 scripts/beat_grid.py sfx/<music_file>
. It plots the sub-120 Hz waveform (where the kick drum lives) against the detected beat grid, detects off-beat lock numerically, and writes
beats.json
. Open
beatgrid.png
: red lines must sit ON the kick spikes. If they don't, shift the whole grid by half a beat interval (the script checks this numerically and shifts automatically when the half-beat alignment scores >5% higher).
运行
python3 scripts/beat_grid.py sfx/<music_file>
。该脚本会将低于 120 Hz 的波形(底鼓所在频段)与检测到的节拍网格叠加绘制,以数值方式检测节拍锁定偏差,并写入
beats.json
。打开
beatgrid.png
:红线必须位于底鼓波峰上。如果不在,则将整个网格平移半个节拍间隔(脚本会进行数值检查;当半节拍对齐得分高出 5% 以上时,会自动完成平移)。

Step 3 - Put Big Moves on the Beat

第 3 步 - 让大动作落在节拍上

Scene cuts, titles appearing, big animations: place them on beats from
beats.json
. If you can change the animation, snap the cut to the nearest beat. If you can't, shift where the music starts so the existing cuts land on beats (
-itsoffset
/
adelay
on the music input).
场景切换、标题出现、大型动画:将其放置在
beats.json
中的节拍上。如果可以更改动画,将切换点吸附到最近的节拍。如果不能,则平移音乐起点,使现有剪辑点落在节拍上(在音乐输入上使用
-itsoffset
/
adelay
)。

Step 4 - One Ready-Made SFX per Cut and Big Move

第 4 步 - 为每次剪辑和大动作配备一个现成 SFX

Use the project's existing sound library first if it has one; ask the user if a needed sound is missing. Otherwise, run one
sfx_search.py
call per kind of sound: whoosh for movement, pop for things appearing, click for clicks, typing sounds for typing. Pick the best fit for each shot's action from the shortlist, and download each pick with
sfx_fetch.py
.
如果项目已有声音库,请先使用;如果缺少所需声音,则询问用户。否则,针对每种声音类型运行一次
scripts/sfx_search.py
:移动用 whoosh、物品出现用 pop、点击用 click、输入文字用 typing sounds。从候选列表中为每个镜头的动作选择最合适的声音,并使用
scripts/sfx_fetch.py
下载每个所选文件。

Step 5 - Mix with the Right Hierarchy

第 5 步 - 按正确层级混音

  • Voiceover is the loudest layer; music drops while someone talks (sidechain duck or manual volume automation).
  • Sound effects sit above the music, and source files arrive at wildly different loudness - normalize every layer by measurement, never fixed volume multipliers:
    • SFX one-shots peak-normalized to -3 dBTP with
      scripts/sfx_normalize.py
      (one-shots cut through by transient, so peak not LUFS; and NEVER run
      ffmpeg loudnorm
      on a short SFX - its 3-second buffer destroys short files).
    • Music bed normalized to -20 LUFS.
    • Exact commands are in
      references/ffmpeg_recipes.md
      .
  • Target -16 LUFS integrated, true peak below -4 dBFS on the shipped MP4, so nothing clips after AAC compression or on a phone speaker in mono. Master to
    TP=-4.5
    : the AAC encode adds ~0.3-0.6 dB of overshoot and a
    -4.0
    master comes back off the mux failing the gate.
  • Read
    references/ffmpeg_recipes.md
    for the exact
    ffmpeg
    commands for ducking, SFX placement at beat times, and two-pass
    loudnorm
    .
  • Voiceover 是最响的一层;有人说话时应降低音乐音量(使用 sidechain ducking 或手动音量自动化)。
  • 音效层应高于音乐,而且源文件的响度差异极大——始终通过测量来归一化每一层,绝不使用固定音量倍数:
    • 使用
      scripts/sfx_normalize.py
      将 SFX one-shot 峰值归一化到 -3 dBTP(one-shot 依靠瞬态突出,因此应使用峰值而非 LUFS;并且绝不要对短 SFX 运行
      ffmpeg loudnorm
      ,其 3 秒缓冲会破坏短文件)。
    • 将音乐铺底归一化到 -20 LUFS。
    • 确切命令见
      references/ffmpeg_recipes.md
      。
  • 目标是在交付的 MP4 上达到 -16 LUFS integrated,真峰值低于 -4 dBFS,确保 AAC 压缩后或手机单声道扬声器播放时都不会削波。母带目标设为
    TP=-4.5
    :AAC 编码会增加约 0.3-0.6 dB 的过冲,而
    -4.0
    母带在封装后回读时会超出限制,无法通过门槛。
  • 阅读
    references/ffmpeg_recipes.md
    ,了解用于 ducking、在 cue 时间放置 SFX,以及将
    loudnorm
    双遍处理到
    -16 LUFS
    /
    -4 dBTP
    的确切
    ffmpeg
    命令。

Step 6 - Verify the Export, Then Hand Over Check Points

第 6 步 - 验证导出,然后交付检查点

Run
python3 scripts/verify_mix.py final.mp4 --cue <t1> --cue <t2> ...
with every cue time. It measures the exported MP4 with
ebur128
, grabs one frame before and after every cue from the MP4, and plots the exported waveform with cue lines. Confirm loudness and peak pass, and that each cue sits on a waveform spike and its frames show the cut/title. Then give the user 5 timestamps to check with headphones and the path to
credits.txt
. Do not claim it sounds good.

使用每个 cue 时间运行
python3 scripts/verify_mix.py final.mp4 --cue <t1> --cue <t2> ...
。它会通过
ebur128
测量导出的 MP4,从 MP4 中截取每个 cue 前后各一帧,并绘制带 cue 标线的导出波形。确认响度和峰值通过检查,并确认每个 cue 位于波形波峰上,且对应帧显示剪辑或标题。然后向用户提供 5 个时间戳,供其使用耳机检查,并提供
credits.txt
的路径。不要声称它听起来不错。

Scripts

脚本

ScriptPurpose
scripts/sfx_search.py
Openverse search, license/source filters enforced (
cc0,by,pdm
from
freesound,jamendo
), duration filtering, JSON shortlist with attribution fields
scripts/sfx_fetch.py
Downloads the chosen file into
sfx/
via Python stdlib (
urllib.request
) and appends its verbatim attribution to
credits.txt
scripts/sfx_normalize.py
ebur128
measure + gain + re-measure; peak mode (
-3 dBTP
) for SFX one-shots, LUFS mode for beds - safe where
loudnorm
destroys short files
scripts/beat_grid.py
librosa
beat tracking + numerical off-beat lock check + sub-120 Hz kick-band/grid plot (
beatgrid.png
) +
beats.json
scripts/verify_mix.py
ebur128
loudness + true peak on the exported MP4, before/after cue frame grabs, waveform plot (
verify/waveform.png
),
PASS
/
NEEDS FIX
verdict
脚本用途
scripts/sfx_search.py
Openverse 搜索,强制执行许可证和来源过滤器(来自
freesound,jamendo
的
cc0,by,pdm
),按时长过滤,并输出包含 attribution 字段的 JSON 候选列表
scripts/sfx_fetch.py
使用 Python 标准库(
urllib.request
)将选定文件下载到
sfx/
,并将其原样 attribution 追加到
credits.txt
scripts/sfx_normalize.py
ebur128
测量、增益和重新测量;SFX one-shot 使用峰值模式(
-3 dBTP
),音乐铺底使用 LUFS 模式——可避免
loudnorm
破坏短文件
scripts/beat_grid.py
librosa
节拍追踪、数值化节拍锁定偏差检查、低于 120 Hz 的底鼓频段与网格图(
beatgrid.png
),以及
beats.json
scripts/verify_mix.py
对导出的 MP4 进行
ebur128
响度和真峰值测量、cue 前后帧截取、波形绘制(
verify/waveform.png
),并给出
PASS
/
NEEDS FIX
结论

References

参考资料

  • references/ffmpeg_recipes.md
    - exact
    ffmpeg
    commands for beat-shifting music, placing SFX at cue times, voiceover sidechain ducking, and two-pass
    loudnorm
    to
    -16 LUFS
    /
    -4 dBTP
    . Read it before writing any
    ffmpeg
    command.
  • references/ffmpeg_recipes.md
    - 用于偏移音乐节拍、在 cue 时间放置 SFX、旁白 sidechain ducking,以及将
    loudnorm
    双遍处理到
    -16 LUFS
    /
    -4 dBTP
    的确切
    ffmpeg
    命令。编写任何
    ffmpeg
    命令前先阅读它。