HyperFrames Audio
混音是一组关系,而非处理器的堆叠。两条单独听起来都正确的音轨放在一起可能无法入耳,解决方法几乎从来不是“调低其中一条”,而是要找出它们争夺的是什么,并将其交给需要它的一方。这里的每一种工具都是为了表达其中一种关系而存在。
效果作用于元素上的 data-fx-chain 属性,预览和渲染运行相同的 Web Audio 图 — 工作室环境中的实时上下文,浏览器内部离线上下文中的引擎(它已驱动浏览器)。每种效果只有一种实现,因此你在拖动时听到的就是最终写入的内容。你永远不需要重复调试。
剪辑时间线仍由 /hyperframes-core 处理:音频/视频修剪和源范围使用 data-start、data-duration 和 data-media-start,交叉淡入淡出在不同轨道上的剪辑重叠。此技能控制已放置轨道的淡入/淡出、交叉淡入淡出包络、轨道增益/音量、音量及效果自动化、闪避/旁白音轨切割以及效果链。/media-use 负责资源获取、生成和预处理。
常量 data-playback-rate (0.1..5) 对于音画同步和变调不变速的音频是渲染安全的,前提是匹配的音频/视频元素使用相同的时间、源偏移和速率。不支持源速度渐变,因为没有速率包络;请预处理一个派生的同步资源。HyperFrames 不提供自动波形同步或漂移校正。
如需可复制的剪辑/交叉淡入淡出/时间调整配方,请使用 /hyperframes-core → references/creator-editing-recipes.md。
三个属性承载所有信息,全部位于音频/视频元素本身:
| 属性 | 作用 |
|---|---|
data-fx-chain | 效果,按信号顺序排列 |
data-automation | 此轨道音量或其效果参数的包络 |
data-fx-carve | 切割自身的设置,以便重新推导 |
提供的内置效果家族有:增益、EQ(高通、低通、峰值、搁架)、压缩器、限制器、门限、饱和、延迟、混响、合唱、移相器和位压缩。
每种效果的精确 JSON 结构以及音轨必须满足的规则:references/attributes.md。
每种效果及其参数、范围和单位:references/fx-registry.md。
如何排查无法听到的文件的问题:references/diagnosis.md。
预设、命名任务和一键配置,以及症状到修复的对照表:references/presets.md — 在手动构建链之前请先阅读该文件,因为通常预设或命名任务之一已经指出了问题所在。
如何协同工作
两个创作界面写入这些属性;两个运行时通过相同的构建器读取它们。这个共享的中间层就是预览能够预测渲染结果的原因。
flowchart TB
voice["语音轨道<br/>媒体文件"]
bed["音乐铺垫<br/>媒体文件"]
subgraph AUTHOR["创作 — 唯一写入属性的方式"]
panel["工作室<br/>旁白音轨切割控制"]
script["scripts/carve.mjs<br/>检测配对,默认动态"]
analysis["core/audioCarve.ts<br/>carveProfile · analyseCarveBands<br/>analyseCarveDuck · analyseCarveDynamics"]
panel --> analysis
script --> analysis
end
voice --> analysis
bed --> analysis
subgraph ATTRS["写入铺垫元素"]
carveAttr["data-fx-carve<br/>source · strength · dynamic"]
chainAttr["data-fx-chain<br/>peaking xN + gain,标记为 fromCarve"]
autoAttr["data-automation<br/>每个切割参数对应一个通道"]
end
analysis --> carveAttr
analysis --> chainAttr
analysis --> autoAttr
subgraph SHARED["一种实现,两种读取方式"]
build["audioFxGraph.ts · buildFxChain"]
sched["audioFxAutomation.ts · scheduleChainAutomation"]
end
chainAttr --> build
autoAttr --> sched
build --> preview["预览<br/>实时 AudioContext<br/>attachElementFxChain"]
sched --> preview
build --> render["渲染<br/>无头浏览器中的 OfflineAudioContext<br/>applyAudioFxChain"]
sched --> render
preview --> heard["拖动时听到的内容"]
render --> wav["处理后的 WAV<br/>+ chainTailSeconds 确保混音保留尾部"]
wav --> mix["引擎 · audioMixer<br/>音量通道在此处烘烤到 PCM 中,而非在图结构中"]
mix --> out["最终的混音输出"]
edit["播放过程中编辑属性"] -.->|MutationObserver| preview
切割本身的设置在播放时永远不会被读取 — 它所生成的效果链和通道才是实际播放的内容。data-fx-carve 的存在是为了能够更改现有切割的强度,而不是从滤波器中反向猜测。
在被切割的铺垫内部,信号首先经过衰减部分,然后是电平匹配,最后是你自己构建的任何效果 — 这就是为什么你添加的限制器仍然可以作为最终的限幅器:
flowchart LR
src["解码后的铺垫"] --> p1["峰值滤波器<br/>400 Hz"]
p1 --> p2["峰值滤波器<br/>1 kHz"]
p2 --> p3["峰值滤波器<br/>1.6 kHz"]
p3 --> g["增益<br/>电平匹配"]
g --> hand["你自己的效果<br/>例如限制器"]
hand --> dest["轨道增益,然后输出"]
l1["通道 fx.n1.gain"] -.->|"语音在此频段<br/>电平的包络"| p1
l4["通道 fx.n4.gain"] -.->|"铺垫整体<br/>闪避的程度"| g
静态切割是相同的图结构,但具有固定值且完全没有通道。
首先,找出问题所在
下表从“听起来混浊”开始 — 这假设已经有人听过并说出了这个问题。如果你只是面对一个文件并需要“修复它”,但没有这样的描述,且你又无法试听,那么你必须测量。有一条规则适用于所有情况:
无法诊断单个未知语音的绝对频谱。 共振峰为 ±10 dB,基频范围为 85–255 Hz,句子结尾处下降 5–6 dB。这些现象单独看都像是缺陷,但实际上每一个都是说话者本身的特点。
因此,进行比较,并且要针对 同一个文件内部 的内容进行比较:如果存在干净的原始版本,则与之比较;否则,与停顿部分进行比较 — 间隙中任何可听到的内容都是附加的,间隙的频谱是通道而非语音。与公开的平均频谱或合成控制语音进行比较是行不通的:两个说话者之间的差异比大多数缺陷都要大,在该指南背后的评估中,两个错误的答案正是来自于此。
当没有原始版本也没有可用的静音时,静态音调缺陷实际上是无法确定的。请说明这一点并提供适合的读数,而不是选择其中一个并在此基础上构建效果链。
命令、陷阱和实践案例:references/diagnosis.md。在诊断一个没有人描述过的文件之前,请先阅读它。
从症状开始
一旦你确定了频段和类型,就要准确描述音频的问题所在。大多数糟糕的音频只属于以下一两种,并且每种都有内置的解决方案:
| 听起来像是 | 使用 |
|---|---|
| 底色有嗡嗡声或砰砰声 | rumble-cut,或 80 Hz 的 highpass |
| 低音过重、胸腔感 | 改善浑厚度 任务 (200 Hz) |
| 闷、像隔着一层纸板 | 减少浑浊度 任务 (250 Hz) |
| 听不清单词 | 提高清晰度 任务 (3 kHz),或切割铺垫 |
| 刺耳、令人疲劳 | 柔化刺耳度 任务 (3.2 kHz) |
| 某些单词比其他单词大很多 | 压缩器上的 均衡度,或均衡音量 |
| 句子间的房间混响 | room-gate |
| 语音和音乐互相冲突 | 旁白音轨切割 — 不是对其中任何一个进行 EQ |
| 干燥、听起来没有空间感 | room-tight 或 room-natural |
| 只是显得“业余” | voice-clean,上述四项按顺序组合 |
完整目录、每个预设包含的内容、频段词汇表,以及故意 不 涵盖的内容(去齿音、降噪、音色匹配):references/presets.md。
先减法再加法,滤波后调整电平,电平后处理关系,最后处理特性和限幅。每一步都会改变下一步所“听到”的内容 — 在高通滤波器之前设置的压缩器会把时间浪费在追求隆隆声上。
根据问题而非名称选择效果家族
滤波器(highpass、lowpass、peaking、lowshelf、highshelf)决定允许一个音轨占据哪些频率。这是解决两个音源冲突的首要工具,因为冲突通常发生在频段内:铺垫和语音都想要 1–3 kHz,从铺垫中拿走这个频段对铺垫的损害远小于将整个音轨调低对混音的影响。语音上的高通滤波器是消除隆隆声的标准方法;低通滤波器则故意使声音变暗或变闷。
动态处理(gain、compressor、limiter、gate)决定一个音轨的电平随时间变化的行为。压缩缩小了响与轻之间的距离,这样轻的部分可以提升。限制器是一个天花板 — 它不塑造任何东西,只保证没有信号能通过它。门限移除低于阈值的部分,这就是如何消除短语之间的房间混响的方法。gain 是一个简单的电平级,当一个音轨需要让路时,自动化通道就是用它来实现的。
非线性处理(saturate、bitcrush)改变波形的形状,从而添加原本不存在的谐波。当音轨需要个性和粗粝感而非校正时使用它 — 请记住,它是生成式的:它使薄弱的音源变得更厚实,而不是更干净。
时间类效果(delay、reverb、chorus、phaser)将音轨置于一个空间或赋予其宽度。这些效果最容易破坏混音,因为一个尾部或失调的副本会占据语音所需的空间。在应该位于其他事物的 后面 的音轨上使用它们,并保持湿声量比孤立听起来要低。
效果链是串行的:每个效果处理前一个效果产生的结果。因此,校正性滤波应放在早期,特性处理在中间,限制器放在最后,它才能真正起到天花板的作用。
旁白音轨切割
解决的问题。 音乐铺垫下的语音会使语音难以听清。直接的做法是降低整个铺垫的音量,这虽然有效,但会牺牲铺垫的所有表现力 — 整个旁白期间音乐都会变得绵软无力。但语音并不需要整个频谱。它只需要它实际占据的那几个频段。切割只去除那些频段,这样铺垫就能保留其低频和高频内容,因此当语音仍然清晰可懂时,它仍然是音乐。
这是一种关系,而非一种效果。 设置位于 铺垫 上 — 即被处理的音轨 — 并且它们指定了要听从的语音,就像侧链压缩器一样:你选择要降低音量的音轨,并选择是什么让它降低音量。永远不要将切割放在语音音轨上。 语音针对自身进行切割就是一个错误,而不是微妙的混音选择。
所有的语音,而不是其中的一个。 sources 是一个列表,因为一个铺垫通常在一整个序列下运行 — 旁白、采访回答、第二位主持人。它们在分析之前,会被叠加到铺垫自己的时钟上(mixCarveSources),因此一次分析涵盖了所有的语音:频段来自所有存在的语音,包络在任何语音活动发生时都处于上升状态。从未与铺垫同时播放的语音应被排除在外;它们无法掩蔽它。
一个旋钮。 strength 的取值范围是 0..1,它派生所有参数:切割的深度、频段数量、宽度、更偏向可懂度还是原始语音能量、电平允许下降的程度、目标电平在语音下方的程度。这六个参数在任何真实的混音中都是同步变化的 — 轻柔的切割是在少数频段上进行浅层切割并伴随少量闪避,强烈的切割是在更多频段上进行更深层的切割并伴随更多闪避 — 因此它们被作为一个关系一次写入 carveProfile 中。默认值为 0.25 — 在三个频段中进行 6 dB 的衰减,保留 6 dB 的电平空间,可听得到但不会感觉出现空洞。在 0.5 时,衰减达到 10 dB,此时切割开始被视作一种效果而非为语音腾出空间;0 是纯频谱模式 — 只用一个频段,完全没有电平匹配。
默认进行切割。 在旁白下播放的铺垫想要切割;这不是有时间才做的打磨步骤。放置好两个音轨,运行下面的命令,然后试听。只有在音乐下方没有旁白时才跳过此步骤 — 音乐视频、标题卡、随音轨剪切的蒙太奇。
它总是跟随语音。 没有静态模式:固定的深度会在每个停顿处削弱铺垫,一旦你听到过两者的区别,就不会想要静态模式。每个值都会变成语音本身电平的包络 — 静音时不处理铺垫,响亮的段落将切割推向最大深度 — 这被写入普通的自动化中,这就是为什么通道会显示在时间线上并且之后可以编辑的原因。
电平匹配是其一部分。 频谱切割无法解决铺垫仅仅比语音响的问题。因此,切割还会测量铺垫相对于语音的超量,并写入一个 gain 级:对于静态切割,保持一个固定值;对于动态切割,由包络驱动。该包络故意缓慢释放 — 瞬间恢复到满音量的音乐听起来像是机器在操作。
运行它。 在工作室中,切割是轨道效果链顶部的一个模块 — 语音、强度、动态,以及它生成的分析,都在一个卡片中。每当另一个音轨可能是语音时它就会出现,并且只有一个 候选 音轨在其上的铺垫会被默认以默认强度动态切割:这就是旁白下的铺垫所需要的结果,该模块就是你可以更改或关闭它的地方。如果有多个候选者,则选择器会等待而不是猜测。在无头模式下(这是创作编排而非编辑时的路径):
node <SKILL_DIR>/scripts/carve.mjs --comp index.html
这就是全部命令。它会找到匹配的音频对,如有必要将进行求和,运行分析,将三个属性写入铺垫元素,并让模块准备好进行交互调整。要观察每一步:
node <SKILL_DIR>/scripts/carve.mjs --comp index.html --verbose
要强制覆盖(例如重新运行替换手动编辑):
node <SKILL_DIR>/scripts/carve.mjs --comp index.html --overwrite
它应位于何处
此技能使用 /hyperframes-core 的基础构建模块来获取剪辑、轨道和元素的架构。它根本不接触媒体文件的获取、解码或预处理 — 这些都通过 /media-use 处理 — 并且 /media-use 中的任何内容都不应在此处重复。效果链、自动化快照、参数插值和属性序列化都包含在内。它在工作室和终端模式下运行,对 MutationObserver 的更改做出反应。