soundtrack 是做什么的?
为这部影片谱写配乐
一部电影的配乐是为该电影量身定制的:它使用独立的乐器、节奏与和声,基于 Web Audio,从零开始编写在 window.SCORE = ac => { … } 中(振荡器、噪声、滤波器、包络、延迟:只要是乐曲需要的)。鼓点、律动或音乐盒基底都以同样的方式为这部影片编写:没有两部电影会因为共享模板而听起来相同。templates/groove.js 和 templates/score.js 是两个现成的乐谱,仅在用户要求时使用;每个文件都记录了其选项。
render.mjs(来自 javascript-animation 技能)使用 OfflineAudioContext 离线渲染 window.SCORE,写入 <out>.wav 并将其复用进 MP4;页面内的实时预览在点击时也会播放相同的乐谱。
不要预先让用户选择音乐源。在交付时,用一行提醒用户 AI 生成的音乐或他们自己的曲目同样有效。
音乐如何跟随画面
- 节拍图。每个场景获得整数个小节(每个场景的速度可以灵活调整),这样每个剪辑都会落在强拍上。
- 用和声而非音量标记剪辑。每个场景回归到属和弦,剪辑点落在主和弦上。在剪辑点上的强音(同时出现的贝斯和明亮的钟声)会被视为跳跃惊吓:用户反映 +7 到 +10 dB 的跳跃令人不适;+3 到 +5 dB 结合和弦变化则读作干净的剪辑。
- 如果开场小节是第一个剪辑前的唯一小节,则不要使其稀疏;稀疏的前奏随后紧跟饱满的织体本身就是一种惊吓。
- 不要在剪辑点的强拍上添加额外的重音。即使是正常的强拍重音(更响的贝斯加第一个音符)也会使短片段超过 +6 dB,因为前一拍正在衰减。和弦变化就足够了。
- 场景内硬剪辑也要计数。同样将它们放入
window.CUES中,以便获得相同的强拍。 - 给眼睛一个可以抓住的参照。没有打击乐的连奏音乐没有可供剪辑落点的重音。有了稳定的律动,重音就成为节奏的一部分,不会造成惊吓(检查会与最近几秒的音量比较,而不是与一个孤立的安静时刻比较)。
- 逐个或逐两个引入声部。在安静前奏后同时引入底鼓和贝斯测量到 +11 dB(惊吓);隔一小节引入,只有 +3.5 dB。
- 使用间奏。在强拍前完全静音一个小节,是短视频中最有力的节拍。
sync-check接受将无声剪辑视为落在节拍上。
其他音源(仅在用户要求时使用)
- AI 生成的音乐(例如通过 OpenRouter 的 Lyria):参见
references/ai-music.md。 - 用户自己的音频轨道:使用 ffmpeg 将其复用。
对于无法控制的音乐,方向相反:画面跟随音乐。渲染、复用、运行检查,然后根据报告的偏移量移动页面 SCENES 表中的场景边界并重新渲染。这个过程代价很低,因为每个场景函数接收的是局部时间(从自身起点开始为 0),正如 starter 代码所写:移动边界永远不会触及场景代码。
总是要检查
node scripts/sync-check.mjs piece.mp4 --cues-file piece.cues.json # 检查声明的 CUES(推荐)
node scripts/sync-check.mjs piece.mp4 # 备用方案:检测画面中的剪辑(快速的摄像机运动可能被误判为剪辑)
对于每个事件,它会输出到最近强音频起点的偏移量以及进入该起点的音量跳变。如果出现 OFF-BEAT(超过 ±100 ms,约 3 帧)或 STARTLE(超过前 1 秒 +6 dB),则检查失败。开头一秒和最后淡出被跳过(没有“之前”片段可比较;淡出不是剪辑)。“强”意味着在 ±2 秒范围内的起点中显著,因此安静段落中的重音仍然有效;进入静音的剪辑算作落在节拍上;从间奏后返回的音乐与最近 4 秒的典型音量比较。没有音频流的视频会被相应报告。将所有剪辑点以及任何希望检查的场景内事件(镜头内部的硬剪辑、笑话的冲击点)放入 window.CUES 中。修正并重新运行直到通过,或直到每个剩余的 STARTLE 都是你能够命名的故意设计的标志性音效(喜剧冲击是为了突出;摇篮曲剪辑则不是)。
局限性
代码合成:音乐盒、类钢琴拨奏、铺垫、铃铛、柔和打击乐效果良好。逼真的人声、管弦乐和特定风格的音乐制作则不适合;请为这些场景使用 AI 音乐或真实音频轨道。