卷 I · 诊断 ♩=100 CH 05 05 / 24

校准把不属于你的延迟先减掉

第 2 章量到的那个「偏移」,其实是好几样东西加在一起的:音频从算出来到抵达喇叭要走一段路,画面要刷新,而你的身体本来就习惯提前一点出发。
这几样里,只有最后一样是你的。其余的都是常数,而常数可以被减掉 —— 一次减掉,永久生效,一秒都不用练。
这一章会把浏览器自己承认的延迟读给你看,量出你的常数,再验证一遍减掉之后的效果。这是全书投入产出比最高的十分钟。

输出延迟时钟对齐校准值误差棒什么时候重校

那个偏移是好几样东西加起来的

你按下按键的那一刻,和你听到声音的那一刻,中间隔着一条不短的链路。把它摊开:

从「游戏决定发声」到「你听见」

    1. 音频引擎把这一段样本算出来        几毫秒
    2. 样本进入输出缓冲区                取决于缓冲大小
    3. 声卡 / DAC 把它变成模拟信号        几毫秒
    4. 传到你的耳朵                      几乎瞬时(有线)

从「你决定要动」到「游戏收到输入」

    5. 神经传导 + 肌肉收缩               几十毫秒(这是你的)
    6. 按键行程 + 扫描                   几毫秒
    7. 游戏在下一帧才读到这个输入        最多 16.7ms

这七项里,只有第 5 项是「你」。其余六项全是设备和软件的常数,跟你练得多好一点关系都没有。

而第 2 章那个偏移,量到的是这七项的总和。所以当你看到「我偏早 40ms」的时候,很可能其中一半以上根本不是你的习惯,是链路。

◆ 判词 · 校准治的是链路,不是你

这就是校准这件事的全部意义:把链路那部分挪回原点,让剩下的那部分(你的习惯)成为唯一的变量。

它不会让你的手变稳 —— 抖动一点都不会变,第 3 章那个积分里,校准只动了中心,没动宽度。

但它会把你分布的中心搬回窗口正中间,于是分布的两条尾巴同时缩回来。这是免费的。

一个类比:这跟给秤去皮是一回事

如果上面那张链路表看着有点抽象,换个说法。

你在厨房用电子秤称面粉,先放一个碗上去,秤显示 240 克。这 240 克是碗的,不是面粉的。你不会因为「我称出来 240 克」就以为自己倒了 240 克面粉 —— 你会按一下「去皮」,让它归零,然后再倒。

校准就是按那个「去皮」键。链路的延迟是碗的重量:它一直在那里,稳定、可测、跟你要称的东西无关。没去皮之前,你测到的每一个数都掺着它。

这个类比还能说明另外两件事:

  • 换个碗就要重新去皮 —— 这就是「换设备要重校」。
  • 去皮不会让你倒得更准 —— 秤的精度(对应你的抖动)跟去不去皮毫无关系。

先读一读机器自己承认的部分

有意思的是,你不需要猜链路里的第 1–3 项 —— 浏览器自己会报。

Web Audio 这套接口提供两个数:baseLatency 是音频图处理本身引入的,outputLatency 是从「你安排一个声音」到「它真的从喇叭出来」的全程估计。下面这台机器会把它们读出来,还有一个更重要的东西 —— 量你自己的那个常数。

◗ 先听一下 · 按顺序做这三步

1. 点「读设备」,看这台机器承认多少延迟。

2. 点「量我的偏移」,跟着敲 24 拍。按你平时的手感来,不要刻意修正 —— 一修正就量不到那个常数了。

3. 点「带校准值再量一次」,验证效果。注意看抖动那个数:它应该几乎不变。如果它变了,说明你在第二步刻意修正了。

一个工程细节:两个时钟必须先对齐

这台 demo 里藏着一个不做就全错的步骤,值得单独说,因为它也是所有音游、所有节拍器应用都必须处理的事。

声音由音频硬件的时钟播出,而你的鼠标和键盘事件盖的是另一个时钟的时间戳。这两个时钟原点不同,走速也不完全一致。如果直接拿事件的时间戳去减「我以为声音响的时刻」,量到的就不是你的手,而是两个时钟之间那个毫无意义的差值。

// 错的:用墙上时钟去量音频事件
const err = Date.now() - expectedBeatWallTime;   // 掺进了调度抖动

// 对的:把事件戳换算到音频时钟轴上,再比
function eventTime(ev) {
  // syncOffset = performance.now() − ctx.currentTime * 1000,取一次存起来
  return (ev.timeStamp - syncOffset) / 1000;     // 单位:音频时钟的秒
}
const err = eventTime(ev) - scheduledAudioTime;

还有一层:判定要不要减掉 outputLatency,取决于你想量什么。如果你想量「用户对听到的声音反应得多准」,就该减 —— 因为声音真正到达耳朵的时刻,比你安排它的时刻要晚。本书的引擎把这个换算和这个选择都写在一个地方(clock.jseventTimelatency),这样每个 demo 都不会各写各的。

⚠ 坑 · 用 setTimeout 发声的节拍器,量不了你

还有一个更常见的错误:setInterval 直接触发发声。

定时器的抖动是几十毫秒量级的 —— 也就是说,节拍器自己就在晃,晃得比你的手还厉害。你量到的抖动里,有一大半是它的。

正确做法是「前瞻调度」:定时器只负责往前看一小段,把这段里该响的音符提前排进音频时钟,真正的发声时刻精确到采样点。本书所有会出声的 demo 都走这条路径 —— 否则这本书里所有的测量都不成立。

校准值怎么用到游戏里

量出来的偏移是负的(你偏早),校准值就是它的相反数。具体到操作:

你量到的含义该往哪调
负数,比如 −35ms你总是抢在前面把判定时刻提前,或把你的输入视为延后 35ms
正数,比如 +28ms你总是拖在后面反方向,28ms
绝对值小于两倍误差棒在噪声之内什么都别调

各家游戏对这个设置项的正负号定义不一样,有的叫「判定偏移」,有的叫「音频延迟」,方向还可能相反。所以不要背符号,改完之后回到游戏里试一遍 —— 如果评价变差了,就是符号反了,取个负号再来。

🎮 回到节奏天国 · 如果游戏没有这个设置怎么办

如果你玩的这一作压根没有偏移设置项,这一章依然有用,只是用法变了:

你要把校准值装进自己的身体,而不是装进设置菜单。知道自己「习惯早 35ms」之后,做法不是每次刻意去数「晚一点点」—— 那会把它变成一个需要临场判断的零件,反而更不稳。

正确的做法是:在这本书的 demo 里,用带反馈的方式练几十下。每一下都告诉你早了多少,几十下之后你的身体会自己把中心挪过去,而且是无意识地挪。这比在游戏里瞎调有效得多,因为游戏不告诉你毫秒。

还有一件事:这个系列有一类小游戏是用手写节奏或者需要长按的,它们的输入判定和普通点击未必一样。那类关卡值得单独重新校准一次。

这个方法分不开的两样东西 —— 以及为什么没关系

诚实地说一句:上面这套办法量到的是一个总和,它没办法告诉你其中多少来自设备、多少来自你的身体。

要真的分开,你得在这台机器之外再架一套测量(比如用麦克风录下「声音」和「按键的咔哒声」,看它们的波形差多少)。那属于另一件事,这本书不做。

而幸运的是,你根本不需要分开。因为这两部分在使用上是完全等价的:它们都是常数,都会被同一个校准值一并减掉。你要减的是那个总和,不是它的成分表。

只有一种情况下你会需要分开:当你想把校准值从一台设备搬到另一台的时候。那时候设备那部分变了,你那部分没变,所以整个值不能直接搬。这也正是「换设备要重校」这条规矩的来源 —— 与其分开量,不如换了就重来一次,反正只要十分钟。

你的那一部分,为什么天生是提前的

链路的那几项好理解。但为什么你的那一部分也常常是提前的?

第 1 章的 demo 多半已经让你看到了这个现象:跟着稳定节拍敲的时候,人的偏移往往是负的。这不是失误,是预判系统在正常工作 —— 你的运动系统不是在「等拍」,它是在「赶拍」,而它宁可赶早一点点,也不愿意赶晚。

为什么宁可早?一个直观的解释是:晚是不可挽回的,早还有余地。如果你的目标是「让动作落在那个点上」,那么提前出发、留一点余量,比卡着点出发要稳健得多 —— 后者只要有任何一点意外,就必然迟到。

这个提前量还有个有趣的性质:它会随速度变化。慢的时候提前得更多,快的时候提前得少。第 17 章会用一个 demo 让你在四个速度上各量一遍,把这条曲线画出来。

这就带来了一个实际的麻烦:如果你只在一个速度上校准过,换到差很多的速度就又偏了。所以第 17 章会给一个更实用的建议 —— 在你最常玩的那个速度区间上校准,而不是在最舒服的那个速度上。

校准之后,你会先变差一阵子

最后一个必须提醒的坑,因为很多人会在这里放弃。

改完校准值之后,你有很大概率会觉得手感变差了。这不是你调错了方向,而是一个几乎必然发生的过渡期。

原因很简单:在你不知道自己偏早 35ms 的那些日子里,你的身体已经悄悄适应了这个偏差 —— 它一直在用「感觉早了一点才对」的方式打,而游戏也一直按这个偏差给你反馈。现在你把那 35ms 从系统里拿掉,你的身体还在按老习惯补偿,于是它反而偏到另一边去了。

校准之后的三个阶段

    第 1 天    感觉更别扭。你的身体还在补偿一个已经不存在的偏差。
    第 2-3 天  补偿开始消退。命中率回到校准前的水平。
    之后       补偿完全消失。这时候你才拿到那几个百分点。

所以:校准之后不要立刻根据手感再去改一次。那是这一章最容易毁掉的一步 —— 你会在第 1 天把它改回去,然后永远拿不到那个收益。

正确的做法是:改一次,用三天,第四天再用这本书的 demo 复测一次。如果那时候偏移接近零,说明成了;如果还偏,再调剩下的那部分。

什么时候需要重校,什么时候不需要

校准的价值在于「一次搞定」。如果你每天都在调,那说明你在追噪声(第 2 章那张误差棒的表已经说明了原因)。

需要重校的场合只有四种:

  • 换设备:换了耳机、换了主机、换了显示器。链路变了。
  • 换显示模式:掌机 ↔ 电视、电视的画质模式变了。链路又变了。
  • 换了差很多的速度:第 17 章会量给你看,人的提前量会随速度变化 —— 在 60 BPM 校准好的值,搬到 160 BPM 未必还对。
  • 换了输入方式:从按键换成触屏、从点击换成长按。

不需要重校的场合:今天手感不好、这一关老是过不去、连续两天量到的值差了 5ms。这些都是噪声,或者是别的病(抖动、走位、认错格),改校准值一点用都没有。

◆ 判词 · 校准不治抖动,一分一毫都不治

这是这一章最重要的一句话,也是最容易被忽略的一句。

demo 的第三步会把它演示给你看:把校准值套上去之后,命中率涨了,抖动那个数一点没动。

所以如果你的问题主要是抖动(第 2 章量到的那个数很大),校准能给你的收益是有限的,而且很快就到顶。那时候就该合上这一章,去卷 II。

反过来,如果你的抖动已经很小、偏移却很大 —— 那你是这本书里最幸运的那种读者:你今天就能变强,而且不用练。

✋ 落到手上 · 十分钟清单

1. 用有线设备。(无线的延迟量级比你要测的东西还大。)

2. 电视切到游戏模式;能用掌机模式就用掌机模式。

3. 上面那台 demo,量 24 拍以上,记下偏移和它的误差棒。

4. 偏移绝对值 > 两倍误差棒 → 去游戏设置里调;调完试一关,变差了就取反。

5. 把这个值和「在什么设备、什么模式、什么速度下量的」一起记下来。

6. 然后忘掉它,去练抖动。

卷 I 收尾

到这里,诊断这一卷结束了。你手上应该有这些东西:

  • 你的反应时预判误差,以及它们之间那个倍数(第 1 章);
  • 你的三个数:偏移、抖动、走位,还有「敲到隔壁格」的次数(第 2 章);
  • 这三个数能换算成多少命中率和连击长度(第 3 章);
  • 你在用耳朵还是用眼睛打(第 4 章);
  • 一个已经减掉了链路延迟的校准值(第 5 章)。

其中前四项是知识,最后一项是已经到手的收益。剩下二十章要做的,是把「抖动」这个数往下压,把「走位」和「认错格」这两件事消灭掉。

下一卷从最底层开始:拍。那个必须由你自己发出来、音乐停了也不能停的东西。

而卷 II 的第一句话,会把这一卷的逻辑推到底:如果说校准是把「不属于你的部分」减掉,那么拍就是把「本来就该属于你的部分」拿回来。音乐并不负责给你拍 —— 音乐只是提供线索,那个网格从头到尾都是你自己架起来的。第 7 章有一个专门的自测,会在音乐消失的时候,把这句话变成一个你能看见的数字。

对症CH 05
偏移 抖动 走位 认错格

本章只治一种:偏移。而且是彻底治好、不会复发的那种 —— 只要你别去动它。

带走一句话:校准挪的是分布的中心,不是宽度。它一秒都不能帮你练稳,但它免费。