HyperFrames BGM 实现指南:共享音频引擎的双路由背景音乐系统
2026/9/12 11:29:09 网站建设 项目流程

HyperFrames BGM 实现指南:共享音频引擎的双路由背景音乐系统

【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes

背景音乐(BGM)是 HyperFrames 共享音频引擎(skills/media-use/audio/scripts/audio.mjs)三大能力(TTS / BGM / SFX)之一,遵循"一个合成作品配一首音乐床"的约定。本文以skills/media-use/audio/references/bgm.md为骨架,结合引擎源码与测试,完整讲解 BGM 的两条实现路由——HeyGen 乐库检索(默认)与 Lyria/MusicGen 本地生成(无凭证时的回退),以及从请求驱动、情绪推断、音量决策到失败兜底的完整链路。读完你将掌握:如何通过audio_request.json精确控制 BGM 模式、如何理解并调整默认音量与情绪提示词推断、以及如何确保 BGM 失败永远不会阻断成片渲染。

一、核心架构:一个开关决定两条路由

BGM 由共享音频引擎统一生产,不随各视频工作流(product-launch、general-video、pr-to-video 等)各自复制实现。工作流只写一份中立的audio_request.json,然后调用引擎:

node <SKILL_DIR>/audio/scripts/audio.mjs --request ./audio_request.json --out ./audio_meta.json

引擎内部按一个开关决定走哪条路:是否检测到 HeyGen 凭证(注意是凭证,不是 CLI 本身)。这一点在skills/media-use/audio/scripts/audio.mjs头部注释中写得很明确,并与 TTS、SFX 的降级策略共用同一开关:

  • TTS:HeyGen REST → ElevenLabs → Kokoro(CLI)
  • BGM:HeyGen 检索 → (无凭证)Lyria/MusicGen 生成
  • SFX:HeyGen 检索 → (无凭证)内置 19 个文件库

两条 BGM 路由分别是:

  1. HeyGen 检索(默认,有凭证时):按情绪(mood)搜索 HeyGen 音乐目录,下载排名最高的曲目。不涉及生成,复用与 TTS 相同的~/.heygen凭证或$HEYGEN_API_KEY
  2. 本地生成(回退,无凭证时):由情绪提示词生成 WAV 文件。优先 Google Lyria(云端),其次本地 MusicGen。注意:不存在npx hyperframes bgm命令,引擎直接 spawnskills/media-use/audio/scripts/lyria-recipe.py或内联的 MusicGen Python 脚本。

凭证解析逻辑位于skills/media-use/audio/scripts/lib/heygen.mjsheygenCredential():优先$HEYGEN_API_KEY/$HYPERFRAMES_API_KEY,其次向上最多 5 层目录查找.env,最后读~/.heygen/credentials(OAuth Bearer 或 API key;$HEYGEN_CONFIG_DIR可覆盖目录)。引擎通过heygenOK = heygenCredential() !== null决定默认路由。

二、先跑 Preflight:无凭证不是静默本地生成的绿灯

重要约束:无论是一次性"生成一段 BGM"的请求,还是完整工作流的一部分,在生成前都必须先完成登录 Preflight:运行npx hyperframes auth status,向用户建议登录,然后停下来等待用户选择(登录以使用 HeyGen 音乐库,或离线继续本地生成)。

这条规则与skills/media-use/audio/references/tts.md对本地语音的约束一致,目的都是防止引擎在用户不知情的情况下静默降级到本地路径。npx hyperframes auth status的具体说明可参见skills/media-use/audio/references/requirements.md的凭证解析顺序。

三、从请求驱动:audio_request.json中的bgm字段

bgm对象包含三个可选字段,完整结构如下:

{ "bgm": { "mode": "retrieve", // "retrieve" | "generate" | "none";省略 = auto "query": "calm cinematic underscore", // 情绪,用于检索,也作为生成提示词的兜底种子 "prompt": null, // 显式完整生成提示词;省略则由引擎推断 "blob": "...", // 可选,情绪推断的行业关键词输入 "archetype": "...", // 可选,叙事结构(PAS / BAB / feature-cascade / demo-loop 等) "arc": "..." // 可选,情感弧线(tension→relief / excitement / trust 等) } }

mode的语义是严格模式匹配,引擎在skills/media-use/audio/scripts/audio.mjs中的解析逻辑为:

  • 省略mode(auto):有 HeyGen 凭证走retrieve,否则走generate——这是默认行为。
  • 显式retrieve:严格模式。没有凭证就直接跳过,绝不悄悄转成生成。这样做的原因是:调用方(如 product-launch)可能没有wait-bgm步骤,如果检索悄悄变成 detached 生成,会产生一个调用方永远不去等待的 pending 任务。
  • 显式generate:强制走本地/云端生成。
  • 显式none:禁用 BGM。

query:检索用的情绪词,同时也是生成路径提示词推断的回退种子。推断的优先级链是 storyboard 的music:字段 →messagearc→ 默认"calm cinematic underscore"

prompt:生成路径的显式完整提示词,省略时由引擎的 Mood inference 推断(见第五节)。可选的blob/archetype/arc为推断提供输入。

引擎还支持命令行覆盖:--bgm-mode <mode>--no-bgm--seed-seconds <n>(MusicGen 种子片段时长,默认 28),以及--only tts,bgm,sfx子集运行与合并写入(BGM 可以先行,SFX 稍后补)。输出经skills/media-use/audio/scripts/lib/audio-meta.mjs原子写入audio_meta.json

四、HeyGen 检索路由(默认):搜索 → 取顶 → 下载

4.1 检索与下载流程

检索路径调用searchSounds(query, "music", { limit: 5 }),对应 HeyGen REST 接口GET /audio/sounds?query=<mood>&type=music&limit=5。实现细节见skills/media-use/audio/scripts/lib/heygen.mjssearchSounds()

  • limit上限为 50,此处取 5 条;
  • 音乐类目在服务端默认min_score(0.7)下评分足够高,无需像 SFX 那样调低门槛;
  • 返回按score排名的数组,data字段兼容新数组与旧数字索引两种形状。

引擎取排名第一的结果(results[0]),下载其预签名audio_urlassets/bgm/track.mp3(见skills/media-use/audio/scripts/lib/bgm.mjsretrieveBgm())。整个流程是同步的,引擎返回时文件已在磁盘上,因此bgm_pendingfalse。没有匹配结果则跳过——BGM 是可选项,绝不因它而让渲染失败。

下载完成后写入audio_meta.json的 cue:

{ "path": "assets/bgm/track.mp3", "volume": 0.12, "mode": "retrieve", "query": "calm cinematic underscore", "duration_s": 42.0 }

4.2 默认音量:床(bed)还是主声

volume由引擎的bgmDefaultVolume(hasVoice)决定(skills/media-use/audio/scripts/lib/bgm.mjs导出的常量):

  • BGM_BED_VOLUME = 0.12(≈ -18 dB):有旁白时,BGM 是压在语音之下的"音乐床"。
  • BGM_SILENT_VOLUME = 0.9:无声电影(无语音)时,没有需要避让的人声,BGM 前移到更响的位置。

这两个常量只在bgm.mjs中调优,不散落在调用点。若audio_meta.json中出现显式volume,则永远覆盖默认值。

源码测试skills/media-use/audio/scripts/lib/bgm.test.mjs专门为音量回归而写:历史上带旁白的管线曾以 0.8(≈ -2 dB)输出 BGM,比应有的音乐床高出约 16 dB;测试断言bgmDefaultVolume(true) === 0.12(-18 dB 附近)、无声默认 0.9,并验证旁白场景下 BGM 与人声(0 dBFS)的分离度 ≥ 16 dB。

4.3 短片的编辑点检查

对于短发布视频,不要假设检索文件的开头就是最佳切入点。建议把开头与后续每 5 秒区段对比:如果曲目以安静铺垫开始、而后面某段有更强更干净的音乐入口,就从该段起剪,并施加短的淡入与较长的淡出。每当合成时长变化都要重做此检查——最终音乐文件必须覆盖完整成片,不能有静音尾巴。

五、本地生成路由(回退):Lyria → MusicGen

5.1 分离式生成与等待

生成路径是detached(分离进程)启动的,这样语音合成不会被阻塞;引擎返回时audio_meta.bgm_pending: true,同时写入bgm_pid/bgm_log,直到生成完成。装配(assemble)之前必须先运行等待脚本

node <SKILL_DIR>/audio/scripts/wait-bgm.mjs \ --audio-meta ./audio_meta.json --hyperframes . \ [--timeout-ms 120000] [--interval-ms 2000] [--out ./bgm_status.json]

skills/media-use/audio/scripts/wait-bgm.mjs的行为:轮询输出文件 / 进程 / 日志,检测崩溃,然后写bgm_status.json,其status取值ready | failed | timeout | disabled。关键设计:

  • 正常管线使用永远以 0 退出:BGM 缺失/失败不阻断语音、字幕、SFX 渲染,只有结构性调用错误才退出 1;
  • 崩溃检测把匹配锚定到真实崩溃串(Traceback/IndexError/RuntimeError/index out of range/out of bounds等),避免把良性的渲染提示(如"sample rate out of range, resampling")误判为失败而静默丢弃音乐;
  • timeout-ms 0表示只查一次不等待。

5.2 提供方选择与依赖

顺序提供方环境 / 依赖速度质量
1Google Lyria RealTime$GEMINI_API_KEY$GOOGLE_API_KEY+google-genai(按需自动安装)实时流(≈ 请求时长)生产级
2MusicGen(facebook/musicgen-smallPythontransformers + torch + soundfile + numpy(首次运行约 300 MB;自动安装)CPU 慢;Apple MPS / CUDA 快尚可;仅提示词控制

后端选择以"实际能否运行"为准(skills/media-use/audio/scripts/lib/bgm.mjsgenerateBgmDetached()):

  • 配置了 Lyria 密钥且lyria-recipe.py存在时,若import google.genai失败则先python -m pip install google-genai python-dotenv,安装成功即用 Lyria;
  • 否则探测本地 MusicGen 依赖(import transformers, soundfile, torch, numpy),缺失则自动安装;
  • 两者都不可用时 BGM 被禁用(返回disabled: true并附pip install …提示),语音 + SFX 仍照常渲染

值得注意的工程细节:安装一律用python -m pip而非裸pip——因为 Homebrew/系统 Python 通常只在 PATH 暴露python3/pip3,裸pip会静默 ENOENT 导致"自动安装"从未真正发生;-m pip还保证包装进pyOk()探测的同一个解释器。安装是同步的,但生成本身是 detached 的,所以引擎仍能及时返回。

5.3 种子片段与交叉淡化循环

输出为assets/bgm/track.wav,目标时长 = 语音总时长。MusicGen 只生成一个种子片段(≤28–30 秒,保持在解码器位置编码限制内),然后交叉淡化循环(crossfade-loop)拉长到目标时长,或直接裁剪变短(detached-seed-loop/detached-seed-trim两种 mode),避免逐段拼接产生接缝。内联脚本要点(skills/media-use/audio/scripts/lib/bgm.mjsmusicgenScript()):

  • 峰值归一化到 0.89,避免削波;
  • 循环接缝处用 0.3 秒余弦交叉淡化(fade-out / fade-in 曲线);
  • 首尾施加强度渐入(0.08 s)与较长渐出(0.5 s);
  • 最终防削波后再归一化一次。

Lyria 路径则通过client.aio.live.music.connect(model="models/lyria-realtime-exp")实时流式接收 48 kHz 16-bit 立体声 PCM,攒够目标字节后写成 WAV(见skills/media-use/audio/scripts/lyria-recipe.py)。

六、情绪推断(Mood inference):生成提示词从哪里来

inferBgmPrompt()skills/media-use/audio/scripts/lib/bgm.mjs导出)按三级策略构建提示词:显式prompt优先;否则按行业关键词base→ 叙事archetype塑形 → 情感arc决胜。

第一步——行业关键词匹配 base 与 BPM(匹配blob/query中的关键词):

blob/query中的匹配基础提示词BPM
crypto / nft / web3 / defi / token / blockchainatmospheric electronic, deep bass, futuristic synths, restrained percussion100
finance / fintech / bank / payment / invest / wealthcalm cinematic, soft strings, subtle piano, restrained percussion92
creative / agency / design / studio / art / brandplayful electronic, warm pads, light percussion115
(默认:SaaS / 科技 / 平台)uplifting corporate tech, bright modern piano with synth pads108

第二步——archetype 重塑弧线(源码中的正则分支,还包含一些未在文档表格列出的同义关键词,如exchange/wallet/daoinsurance/treasurymarketing/content等):

  • PAS(pain-agitate-solve)→ "MINOR to MAJOR" 铺垫与解决式构建;
  • BAB / future-pacing → 影院感、上扬能量、MAJOR;
  • feature-cascade → 驱动感、恒定动量,BPM +10(上限 128);
  • demo-loop → 干净聚焦、极简编配,BPM −8(下限 88)。

第三步——情感弧线决胜arc):

  • tension → relief(如frustrat/anxiety/overwhelm/tensionrelief/excite/triumph同时出现):从克制的张力构建到振奋的解决,MINOR to MAJOR;
  • excitement(excit/awe/power/triumph):充满能量与自信,MAJOR;
  • trust / reassurance(trust/ease/clarity/reassur):温暖可靠,BPM −5(下限 85);
  • 兜底:<base>, BPM <bpm>, MAJOR

该函数被导出,工作流适配器可以直接用自身的叙事元数据构建更丰富的提示词;引擎在生成只有普通情绪 query 时也会调用它。

七、Lyria 旋钮:直接使用 recipe 时的调参

引擎侧把 BPM / 调式烘焙进提示词文本(通过上面的推断),传给skills/media-use/audio/scripts/lyria-recipe.py的只有--output/--duration/--prompt三个参数。若直接手动调用 recipe,还可以设置以下旋钮:

参数取值说明
--bpm整数(默认 110)90–110 平静,110–130 有能量
--brightness0–1(默认 0.8)≥0.7 适合宣传片(更明亮)
--density0–1(默认 0.5)越高编配越丰满
--scaleMAJOR/MINOR/PENTATONIC/ …(默认MAJOR调式;传空字符串表示不指定
--negative-prompt文本要排除的风格,作为权重 -1.0 的提示词

实现上,Lyria 使用types.WeightedPrompt(正提示词权重 1.0,负提示词权重 -1.0)与LiveMusicGenerationConfig(bpm、temperature=1.0、可选 density/brightness/scale),温度固定 1.0。MusicGen 忽略以上全部旋钮——它的控制入口只有提示词本身,所以情绪要写进 prompt。

八、失败模式总览:BGM 永不阻断渲染

失败场景行为
检索无音乐匹配bgm: null,记录 anomaly,渲染照常继续(无 BGM)。
显式retrieve但无凭证跳过(不静默转生成)。改用mode: generate或省略mode走 auto。
生成路径但 Lyria / MusicGen 都不可运行BGM 禁用并附pip install …提示;语音 + SFX 仍渲染。
装配时生成仍在进行bgm_pending: truewait-bgm.mjs先等待/检查并写bgm_status.json
生成进程崩溃wait-bgm.mjsbgm_status.json { status: "failed" }<audio>轨道被省略。

引擎把所有非致命问题记入 anomaly 列表并在结束时打印(skills/media-use/audio/scripts/audio.mjs尾部输出),但任何 BGM 失败都不会阻止成片渲染——这是贯穿两条路由的根本设计原则。

九、实践要点速查

  1. 先 Preflightnpx hyperframes auth status→ 建议登录 → 停下等用户选择,不要静默走本地生成。
  2. auto 模式下:有 HeyGen 凭证即检索乐库(默认"calm cinematic underscore"),无凭证即本地/云端生成;显式retrieve永不静默降级
  3. 短片编辑点:别迷信文件开头,对照后续五秒区段选最强入口,配淡入淡出;时长变化后重检,保证音乐盖满成片。
  4. 音量:旁白片默认 0.12(≈ -18 dB)音乐床,无声片默认 0.9;要调改bgm.mjs中的BGM_BED_VOLUME/BGM_SILENT_VOLUMEaudio_meta.json显式volume优先。
  5. 生成路径务必先 wait:装配前运行wait-bgm.mjs,用bgm_status.json判定ready | failed | timeout | disabled
  6. 调情绪:给blob/archetype/arc喂叙事元数据,或直接给prompt;MusicGen 只认提示词,Lyria 直调才认--bpm/--brightness/--density/--scale等旋钮。

延伸阅读:skills/media-use/references/audio.md(音频引擎总览与调用方式)、skills/media-use/audio/references/sfx.md(音效)、skills/media-use/audio/references/tts.md(语音)、skills/media-use/SKILL.md(media-use 技能总入口与 Preflight)。

【免费下载链接】hyperframesWrite HTML. Render video. Built for agents.项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询