mcpField
H
hyperframes-audio

hyperframes-audio

github.com/ryu1845创意与媒体016 次安装1 周前更新
代码仓库

关于 hyperframes-audio

hyperframes-audio 是用于处理 HyperFrames 音轨的技能,涵盖效果链、自动化及旁白与音乐的平衡。预览和渲染共用音频处理图,减少两者间的差异。

主要功能

  1. 01串行音频效果链
  2. 02音轨淡入淡出、增益与自动化
  3. 03旁白 carve 与闪避
  4. 04基于预设的音频修正
  5. 05预览与渲染共用处理图

适用场景

  1. 01降低人声中的低频轰鸣或刺耳感
  2. 02让旁白下的音乐保持清晰
  3. 03随时间自动调整音轨音量

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ryu1845/hyperframes --skill hyperframes-audio

安装后在 Claude Code 中输入/hyperframes-audio确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
attributes.md
diagnosis.md
fx-registry.md
presets.md
scripts/
carve.mjs
carve.test.mjs
scripts/lib/
main-module.mjs

详细介绍

插件安装: 如果此技能位于 HyperFrames 插件中,请在执行设置或检查更新命令之前,遵循 插件执行规则。独立安装请继续使用下方的更新说明。

HyperFrames 音频

混音是一组关系,而不是一叠处理器。两条音轨各自听起来都不错,合在一起却可能无法收听。解决办法几乎从来都不是“把其中一条调低”,而是找出它们争夺的频段,并将其留给更需要的一条。这里的每个工具都是为了表达其中一种关系。

效果通过 data-fx-chain 挂载在元素上,预览和渲染使用相同的 Web Audio 图:工作室在实时环境中运行,引擎则在浏览器驱动的离线环境中运行。每种效果只有一种实现,因此拖动时间轴时听到的效果就是最终写入的效果。无需调校两次。

片段时间仍由 /hyperframes-core 负责:音视频裁剪和源范围使用 data-start、data-duration 和 data-media-start,交叉淡化则通过不同轨道上的片段重叠实现。此技能负责已放置轨道的淡入/淡出、交叉淡化包络、轨道增益/轨道音量、音量和效果自动化、闪避/旁白留位以及效果链。/media-use 负责素材来源、生成和预处理。

当匹配的音频/视频元素使用相同的时间设置、源偏移和速率时,恒定的 data-playback-rate(0.1..10)可安全用于渲染画面和保留音高的声音。速度渐变是 data-automation 中的 rate 通道(参见 docs/reference/speed-ramps);它优先于恒定速率,并在预览和渲染中保留音高。HyperFrames 不提供自动波形同步或漂移校正功能。 如需可复制的剪辑/交叉淡化/变速配方,请使用 /hyperframes-core → references/creator-editing-recipes.md。

三个属性就能承载所有内容,可设在音频/视频元素本身上;前两个也可设在 <hf-audio-group> 总线上(参见“一条总线承载多条轨道”):

属性内容
data-fx-chain效果,按信号处理顺序排列
data-automation此轨道音量或其效果参数的包络
data-fx-carvecarve 自身的设置,以便重新推导

已提供的效果类别包括增益、均衡器(高通、低通、峰值、搁架)、压缩器、限制器、truepeak(前瞻式真峰值限制器)、噪声门、饱和、延迟、混响、合唱、移相和位压缩。

每种效果的确切 JSON 格式及通道必须满足的规则:references/attributes.md。 每种效果的参数、范围和单位:references/fx-registry.md。 如何排查无法试听的文件: references/diagnosis.md。 预设、命名任务和单旋钮配置,以及症状到修复方案表: references/presets.md — 手动构建效果链之前请先阅读,因为通常已有预设或命名任务能直接解决对应问题。

各部分如何配合

两种创作界面会写入这些属性;两个运行时会通过相同的构建器读取这些属性。正是这个共享的中间层,让预览能够预测渲染结果。

flowchart TB
  voice["voice track<br/>media file"]
  bed["music bed<br/>media file"]

  subgraph AUTHOR["Authoring — the only things that write attributes"]
    panel["Studio<br/>Voiceover carve control"]
    script["scripts/carve.mjs<br/>detects the pair"]
    analysis["core/audioCarve.ts<br/>carveProfile · analyseCarveBands<br/>analyseCarveDuck · analyseCarveDynamics"]
    panel --> analysis
    script --> analysis
  end

  voice --> analysis
  bed --> analysis

  subgraph ATTRS["Written onto the bed element"]
    carveAttr["data-fx-carve<br/>sources · strength"]
    chainAttr["data-fx-chain<br/>peaking xN + gain, tagged fromCarve"]
    autoAttr["data-automation<br/>a lane per carved parameter"]
  end

  analysis --> carveAttr
  analysis --> chainAttr
  analysis --> autoAttr

  subgraph SHARED["One implementation, read by both"]
    build["audioFxGraph.ts · buildFxChain"]
    sched["audioFxAutomation.ts · scheduleChainAutomation"]
  end

  chainAttr --> build
  autoAttr --> sched

  build --> preview["Preview<br/>live AudioContext<br/>attachElementFxChain"]
  sched --> preview
  build --> render["Render<br/>OfflineAudioContext in the headless browser<br/>applyAudioFxChain"]
  sched --> render

  preview --> heard["what you hear while scrubbing"]
  render --> wav["processed WAV<br/>+ chainTailSeconds so the mix lets the tail through"]
  wav --> mix["engine · audioMixer<br/>volume lane baked into the PCM here, not in the graph"]
  mix --> out["the rendered mix"]

  edit["editing the attribute mid-playback"] -.->|MutationObserver| preview

播放时绝不会读取 carve 自身的设置;实际播放的是它生成的效果链和通道。data-fx-carve 的作用是让你能调整现有 carve 的强度,而不用从滤波器设置中反向猜测。

在经过 carve 处理的底层音轨中,信号会先经过衰减,再进行电平匹配,最后经过你自行构建的处理——因此,你添加的限制器仍会作为最后一道限幅:

flowchart LR
  src["decoded bed"] --> p1["peaking<br/>400 Hz"]
  p1 --> p2["peaking<br/>1 kHz"]
  p2 --> p3["peaking<br/>1.6 kHz"]
  p3 --> g["gain<br/>level match"]
  g --> hand["your own effects<br/>e.g. limiter"]
  hand --> dest["track gain, then out"]

  l1["lane fx.n1.gain"] -.->|"envelope of the voice's<br/>level in that band"| p1
  l4["lane fx.n4.gain"] -.->|"how far the bed<br/>ducks overall"| 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
人声和音乐互相干扰旁白挖频——不要对其中任何一方单独使用均衡器
声音干涩,缺少空间感room-tight 或 room-natural
就是听起来“不专业”voice-clean,按顺序组合以上四种处理

完整目录、每个预设包含的内容、频段术语,以及明确不涵盖的内容(去齿音、降噪、音色匹配):references/presets.md。

先削减再增强,滤波后再调整电平,电平调整后再处理相互关系,最后再处理音色和上限。每一步都会改变下一步听到的内容——如果先设置压缩器再使用高通滤波器,它就会一直忙着追逐隆隆声。

根据问题选择效果类别,而不是看名称

滤波器(highpass、lowpass、peaking、lowshelf、highshelf)决定一条音轨可以占据哪些频率。当两个音源发生冲突时,这是首先该用的工具,因为冲突发生在频段上:底音和人声都需要 1–3 kHz,而从底音中削减这些频率,对底音的影响远小于调低整个音源对混音的影响。对人声使用高通滤波是消除隆隆声的标准做法;低通滤波则会刻意让声音变暗或变闷。

动态处理(gain、compressor、limiter、truepeak、gate)决定一条音轨的音量如何随时间变化。压缩会缩小大声与轻声部分之间的差距,让轻声部分得以提高。限制器会将峰值压向上限,不会塑造其他部分。limiter 会跟随音量,且没有前瞻功能,因此快速峰值或采样间峰值可能会超过上限;若要满足交付上限,请使用 truepeak,它会进行前瞻并测量采样间峰值。它会将 4x 估算值限制在上限,而不是限制波形本身,因此全频带噪声最终可能会高出 1.7 dB:如果交付限制严格,请将上限至少设在限制值以下 2 dB。噪声门会消除低于阈值的声音,用于在乐句之间静音房间底噪。gain 是简单的音量处理级;当音轨需要让出空间时,自动化曲线控制的就是它。

非线性处理(saturate、bitcrush)会改变波形形状,从而增加原本不存在的谐波。当音轨需要的是个性或粗粝感,而不是修正时,就可以使用它——但要记住,这是生成性处理:它能让单薄的音源变得更厚实,却不会让它更干净。

时间效果(delay、reverb、chorus、phaser)会为音轨营造空间感或增加宽度。这些效果最容易破坏混音,因为尾音或失谐的副本会占据人声需要的同一空间。将它们用于应该位于其他声音_后方_的音源,并把湿声量调得比单独聆听时感觉合适的程度更低。

效果链是串行的:每个效果都会处理前一个效果的输出。因此,修正性滤波应放在前面,音色塑造放在中间,限制器放在最后,这样才能真正发挥限幅作用。

旁白频谱挖空

解决的问题。 人声下方铺一层音乐,会让人声难以听清。通常的做法是压低整层音乐,这确实有效,但也会让音乐失去全部存在感——整段旁白期间,音乐都显得软绵无力。但人声并不需要整个频谱,只需要它实际占据的几个频段。Carve 只挖空这些频段,同时保留音乐的低频和高频,因此人声清晰可辨时,音乐也依然像音乐。

这是一种关系,而不是一种效果。 设置位于_音乐底层_——也就是接受处理的音轨——并指定要监听的人声,和侧链压缩器完全一样:选择要变小声的音轨,再选择让它变小声的声音。绝不要在人声音轨上设置 carve。 人声相对于自身挖空,是个 bug,不是什么微妙的混音选择。

覆盖所有人声,而不是只覆盖其中一段。 sources 是一个列表,因为音乐底层通常会贯穿一整段内容——旁白、采访回答、第二位主持人。在进行任何测量之前,它们会先按音乐底层自己的时间轴混合在一起(mixCarveSources),因此一次分析就能覆盖所有人声:频段根据所有人声内容确定,只要有任何人声出现,包络就会上升。音乐底层播放时从未出现的人声会被排除;它们不会造成遮蔽。

针对多个片段 id 进行 carve 是错误的。应将片段分组,再针对该组进行 carve。 这是一个不变量,而非建议。逐个列出片段就必须确保一个不漏,而且只有在下次编辑之前才能保持正确——之后新增的第四段旁白会在 carve 不知情的情况下播放,而音乐底层也会悄无声息地漏掉对它的压低。改为指定分组后,分析时会解析分组成员,因此之后添加到组中的片段也会自动覆盖,无需改动 sources:


<audio id="vo-intro" data-audio-group="voiceover" …></audio>
<audio id="vo-middle" data-audio-group="voiceover" …></audio>
<audio id="vo-outro" data-audio-group="voiceover" …></audio>

<audio id="music" data-fx-carve='{"enabled":true,"sources":["voiceover"],"strength":0.8}' …></audio>

如果 sources 列表中列出的是两个或更多普通片段 id,而不是一个分组,audio_carve_ungrouped_sources lint 规则就会报错——这种写法仍然有效,但新增片段后会悄悄失效。

Carve 分组中只放人声:不要放音乐底层、音效或音乐片段。 sources 中的分组 id 会在每次分析时解析为_当前_所有成员,因此之后得到的是你指定的分组,而不是编写时测量过的那些音轨。这会带来两种问题:

  • 音乐底层在自己的源分组中。 它会被当作人声输入给自身,并针对自己的内容进行 carve——“绝不要让音轨针对自身进行 carve”的问题会在下一次重新分析时出现。
  • 人声分组中有音效或音乐片段。 下一次分析时,这些片段会进入侧链,音乐底层便开始跟着呼啸声压低,即使写入该属性的那次运行从未测量过它们。

在写入 carve 的那一刻,这两种情况都不可见:分析只会混合检测到的人声,不会重新解析分组,因此第一次分析确实正确,只有下一次才会出错。因此,每种角色都应使用自己的分组——音乐底层用 music,旁白用 voiceover,音效用 sfx——并确保 sources 中指定的分组里只包含人声。

当 carve.mjs 发现上述任一情况时,它会拒绝写入分组形式,记录片段 id,并在 stderr 中指出哪个成员导致了问题。随后,audio_carve_ungrouped_sources 规则会指向编排本身,而不是让 CLI 悄悄保存一个范围比实际测量更大的 carve。

本次运行遗漏的人声不属于上述情况,也不会阻止使用分组形式:carve.mjs 只分析与音乐底层重叠的人声;无需修改 sources 就能自动覆盖之后才播放的片段,这正是指定分组的全部意义。

多条音轨共用一个总线

如上所述,仅凭分组成员关系就足以进行 carve;但如果添加一个 id 相同的 <hf-audio-group> 元素,该分组就会成为真正的子混音总线:所有成员共用一条效果链、一个推子和一条自动化时间轴。

<hf-audio-group
  id="voiceover"
  data-label="Voiceover"
  data-volume="0.9"
  data-fx-chain='{"version":1,"nodes":[
    {"type":"compressor","id":"g1","params":{"threshold":-18,"ratio":3}},
    {"type":"peaking","id":"g2","params":{"frequency":3000,"gain":2,"q":1}}]}'
></hf-audio-group>

<audio id="vo-intro" data-audio-group="voiceover" …></audio>
<audio id="vo-middle" data-audio-group="voiceover" …></audio>

当多个音轨需要相同处理时,使用总线。 四段旁白片段都需要相同的压缩器,就意味着要维护四条保持同步的处理链;只要编辑其中一条,它们就会产生偏差。放到总线上,就只需一条处理链,而且压缩器听到的是完整的人声,而不是孤立的单个片段——这正是关键,因为压缩器无法跟随它只听到三分之一的序列。真正属于单个片段的处理仍应留在片段上:例如某段噪声较大的录音需要单独使用去齿音器。

总线上的属性作用
data-fx-chain对合并后的成员应用一条处理链
data-automation总线上的包络,使用合成时间
data-volume所有成员共用一个推子(默认值为 1)
data-label显示名称;未设置时回退为 id
data-hidden将所有成员从混音中移除

组自动化使用合成时间,而非片段时间。 总线没有 data-start——成员到达总线时已经处于各自在合成中的位置——因此,组通道中的 t: 0 表示合成的起点,而不是任何片段的起点。片段上的通道使用片段本地时间;相同数字在两者中表示不同的时刻。将包络从片段移到总线上时,这是唯一必须处理正确的事项。

挖空处理应留在片段上。 data-fx-carve 不是组属性。被挖空的背景音乐是一条独立音轨,应由该音轨携带 data-fx-carve——按上述规则指向某个组。组与挖空处理在 sources 中关联,而不是放在同一个元素上。将挖空处理写在总线上,相当于把一个效果拆成两半并应用两次:电平部分会测量背景音乐自身的音频,但总线上没有背景音乐音频,因此只有滤波器会生效;而总线及其成员属于同一条信号路径,所以背景音乐会经过总线滤波器,也会经过自身的滤波器。audio_group_carve_attr lint 规则会检测这种情况。

对整个混音应用一个效果:主总线。 一个片段只能指定一个组,因此对所有内容进行限制或均衡不能通过组来实现。将其放在顶层合成根节点的 data-fx-chain 中:它会在每个组的处理链和推子之后,对所有片段和组的总和运行一次。常见用途是设置交付峰值上限——将 truepeak 放在主总线处理链的最后。只有顶层根节点会被视为主总线;子合成根节点上的 data-fx-chain 不会在父合成中应用。主总线不支持自动化。

一个片段不等于一条总线。 组的用途是让多条音轨共用一条处理链、一个推子和一个时钟。将单个片段包装在总线中并无益处,因为片段自身的 data-fx-chain 已经能做到同样的事;而且这会让后续编辑需要修改的地方加倍。唯一值得这样做的理由是:总线的自动化时钟使用合成时间,因此,若要让单个片段上的通道按合成时间计时,可以使用只包含该片段的总线。

一个旋钮。 strength 的取值范围为 0..1,并由它推导出所有参数:削减深度、频段数量、带宽、优先提高清晰度而非原始人声能量的程度、电平允许降低的幅度,以及目标电平相对人声的低出程度。在实际混音中,这六项会一同变化——轻柔的挖空处理会在少数频段中进行浅削减,并只做少量闪避;较强的处理则会在更多频段中进行更深的削减——因此它们共同构成一个关系,并只在 carveProfile 中定义一次。carve.mjs 的默认值为 0.8——在 250 Hz 到 2.5 kHz 之间使用六个频段,每个频段约削减 7 dB,在 1.6 kHz 处削减 15 dB,并留出 19 dB 的电平余量——因为旁白下方的背景音乐首先要为人声让位,其次才是音乐;0.25(三个频段中削减 6 dB,并留出 6 dB 的余量)虽然让背景音乐保持存在感,却仍会与人声争抢空间,实际效果被认为太弱。取值为 0.5 时,削减达到 10 dB,这时挖空处理开始听起来像一种效果,而不是为人声腾出空间。当背景音乐是重点、而人声较少时,应降低 strength。0 仅进行频谱处理——一个频段,完全不匹配电平。 默认进行频谱挖空——只要音乐在语音下方播放,就必须这样做。 任何语音轨道(旁白、虚拟形象语音、访谈、画外音)下方的音乐底轨,都应在混音收尾时进行频谱挖空,而不是有时间才做的润色步骤。放置两条轨道,运行下面的命令(默认强度为 0.8;如果检测结果有误,添加 --bed / --voice),使用 npx hyperframes check 确认写入的 data-fx-carve、data-fx-chain 和 data-automation,然后再渲染。仅做音量闪避并不算完成混音:这样会让语音和音乐底轨在 1–3 kHz 频段相互争抢,还会让音乐底轨在整个画外音期间都失去存在感。只有音乐下方没有语音时才跳过频谱挖空——例如音乐视频、标题卡片、按音乐剪辑的蒙太奇。

它始终跟随语音变化。 没有静态模式:固定的挖空深度会在每次停顿时削薄音乐底轨;一旦听过两种效果,就不会想再用静态模式。每个数值都会变成由语音自身音量驱动的包络——静音时不影响音乐底轨,语音段落较响时则将挖空推至最大深度——并写为普通自动化,因此这些自动化轨道会显示在时间轴中,之后也可以编辑。

音量匹配也是其中一环。 频谱挖空无法修复音量本就高于语音的音乐底轨。因此,挖空功能还会测量音乐底轨比语音高出多少,并写入由包络驱动的 gain 阶段。这个包络会刻意缓慢释放——单词一结束,音乐就立刻恢复到全音量,听起来会像机器在处理。

运行方式。 在 Studio 中,频谱挖空是轨道效果架顶部的一个模块——语音、强度和生成的分析结果都显示在同一张卡片中。只要另一条轨道可能是语音,就会显示该模块;如果音乐底轨上方恰好只有一个候选轨道,就会默认进行挖空,并使用默认强度: 这正是旁白下方的音乐底轨所需的效果,而该模块可用于更改强度或关闭效果。候选轨道有多个时,选择器会等待你选择,而不是自行猜测。 无头模式—— 也就是编写合成而非编辑合成时使用的路径:

node <SKILL_DIR>/scripts/carve.mjs --comp index.html

这就是完整命令。它会自行查找语音和音乐底轨,使用默认强度进行挖空,并打印它的判断结果:

bed    music-bed (name looks like music)
voice  narration (only track left)
carve  strength 0.8, 1 voice
bands  250Hz -7.4dB q2.06, 400Hz -7.4dB q2.06, 630Hz -7.4dB q2.06, 1000Hz -7.4dB q2.06, 1600Hz -14.8dB q2.06, 2500Hz -7.4dB q2.06
level  273-point envelope, floor -19.2 dB

自动选择有误时,使用 --bed / --voice 指定轨道(可重复使用);使用 --strength 调整效果强度;使用 --dry-run 查看报告而不写入任何内容。

它如何选择轨道。 首先看名称,因为这是你已提供的信息,而且判断依据清晰可解释——核心中的 classifyAudioName,与 Studio 自带选择器使用的分类器相同,因此两者不会得出不同结果。ID 或文件名看起来像音乐的轨道(music、bgm、bed、score 等)会被视为音乐底轨;其他所有在其上播放且不像音效的轨道都会被视为语音。优先选择音频元素:只有在没有音频轨道可作为语音时,或合成中的所有 B-roll 片段都会被视为有人说话时,才会将视频计入。如果无法判断哪条轨道是音乐底轨,它会拒绝执行,而不是对错误的轨道进行挖空——手动输入一个 ID 并不费事。

使用与面板相同的分析函数,因此结果完全一致。需要 PATH 中有 ffmpeg,并且项目中已安装 @hyperframes/core(npm i -D @hyperframes/core)——CLI 会将 core 内联,而不是随包提供,因此无法从那里借用。

它写入的内容是一组普通的峰值滤波器链和一个增益阶段,并标记为 fromCarve。这个标记至关重要:重新运行时会替换之前的挖空效果,同时将你手动创建的所有效果——以及你手动绘制的所有自动化轨道——原封不动地保留在原处。因此,以新的强度重新进行频谱挖空既安全又可重复;data-fx-carve 则用于读取设置,而不必根据滤波器猜测。

自动化

一个自动化轨道是在一个参数上设置的一组断点:{t, v},时间单位为片段内的秒数,值的单位为参数自身的单位。目标可以是用于控制音轨音量的 volume,也可以是用于控制效果旋钮的 fx.<nodeId>.<param>。

只有部分参数可以自动化;在其他参数上设置自动化轨道不会生效,且不会给出提示。 由 Web Audio AudioParam 支持的旋钮才能自动化。基于 worklet 的效果器——compressor、limiter、truepeak、gate、bitcrush——均不提供任何此类参数,因此这些效果器的任何参数都无法随时间变化:若要让压缩器的行为随时间改变,请改为自动化它之前的 gain 阶段。references/fx-registry.md 列出了每个参数。

验证

几乎没有静态检查会覆盖混音。lint 工具会读取 data-automation,但只检查一种冲突——audio_volume_double_automation:音轨上有音量自动化轨道,同时也有针对 volume 的 GSAP 补间动画;此时自动化轨道优先生效,补间动画会被忽略。它还会检查 audio_volume_tween_overrides_gain:音轨设置了 data-volume,同时其 volume 有补间动画;此时补间动画的值是绝对值,会替代音量增益,而非对其进行缩放。除此之外,它完全不会验证效果链或效果自动化轨道。真正负责检查的是渲染:无法解析的效果链会导致整个混音失败,而不是悄悄写入干声,因为听起来似乎合理、实际却有误的混音,比直接拒绝更糟。预览则有意采用相反的做法:无法读取效果链时会播放干声,以便继续编辑编曲。

若自动化轨道指向效果链中不存在的节点,读取时会将其删除,而不会报错——因此,nodeId 拼写错误会让包络悄无声息地丢失。请从效果链中读取节点 ID,而不要猜测生成的 ID。

带有尾音的效果器(reverb、delay)会让渲染后的音轨长于源音频,效果链会告知混音需要延长多少。因此,带混响的铺底音轨不再恰好在其 data-duration 处结束,这是预期行为,并非 bug。

除此之外,验证混音的方式是渲染并试听。对于挖空处理,人声应清晰可辨,同时铺底音轨不应听起来空洞;铺底音轨还应在乐句间恢复音量,而不是始终保持平坦。如果铺底音轨在人声下方听起来像被挖出缺口,而不仅仅是音量变小,说明强度过高——这是最容易通过听感辨认的故障模式。

评论

支持 Markdown