The heal is 480 ms long and the team cannot agree on why it feels late. The trigger frame is right, the file is trimmed to the first sample, and the total length is inside the budget. What is late is the point where the ear decides that something happened.
That point is set in the first fifty milliseconds, and it is not a function of file length. The budget described in the three-tenths-of-a-second pickup cue is a ceiling: it tells you when the cue has overstayed, not when it begins to register. A heal can clear the ceiling and still feel slow.
The Onset Is a Separate Layer, Not the Left Edge of an Envelope
Render the same 420 ms body twice. Version A opens with a three-millisecond noise burst, high-passed near 2 kHz, and then swells. Version B fades in as a low swell over forty milliseconds. Same duration, same peak, same body, and in a blind comparison they land roughly forty milliseconds apart in perceived timing.
The ear tends to fuse energy that arrives inside twenty to thirty milliseconds and separate events after that. Whatever fills that window becomes the anchor for the body, the pitch gesture and the tail. When the anchor is a slow rise, everything behind it inherits the delay.
Above 1 kHz, Energy Arrives First and Survives the Mix
High frequencies are resolved earlier along the cochlea and need less integration time than lows. The first impression of a cue is therefore carried by whichever part of the spectrum can report fastest, not by whichever part is loudest.
The arithmetic is easy to check. An 80 Hz tone has a 12.5 ms period, and a definite pitch needs several periods, so a low swell spends twenty-five to forty milliseconds before it has said anything. A 3 kHz transient completes a cycle in about a third of a millisecond.
Masking pushes the same way. Combat beds, engines and music crowd the band between 80 Hz and 800 Hz, while 1.5 kHz to 4 kHz stays comparatively open. Laptop and phone speakers roll off below a few hundred hertz and often peak somewhere around 2 to 4 kHz.
A workable transient layer: high-passed between 1.2 kHz and 2 kHz, four to eight milliseconds long, six to ten decibels under the peak of the body. Enough to mark the frame, not enough to become its own event.
Three Milliseconds of Anti-Click Is Hygiene; Thirty Is an Attack
Clicks come from discontinuities, and the usual fix is a short fade at the head of the file. The same control also shapes the attack, which is why it gets left too long: it removes the click audibly and the responsiveness silently.
Invert the ramp length to find where the line sits. Two milliseconds is roughly half a cycle at 500 Hz, fast enough to read as an edge. Thirty milliseconds is a full cycle at 33 Hz, slower than any transient needs to be. Somewhere between eight and twelve milliseconds the ramp stops being hygiene and starts being the attack.
What the Defaults Do
Check the defaults you inherited. DAWs often add a few milliseconds on a trim, sox needs it stated as in a three-millisecond fade, and synth envelopes start at ten milliseconds or more because that setting suits pads. In Unity the ramp lives in the generated clip, in FMOD it is the AHDSR attack on the event, and in Wwise it is the attack on the source or the ADSR inside the container.
Read the waveform rather than the setting. A heal should reach most of its level inside two milliseconds, with no visible run-up from the left edge.
That check catches most slow heals before anyone opens a profiler. If the waveform shows a two-millisecond edge and the build still feels late, the problem is downstream.
The Same Swell Reads Later Without a Click in Front of It
Take a 300 ms body at minus three decibels and render two versions: a sixty-millisecond ramp from silence, and the identical body behind a five-millisecond filtered noise burst. Match loudness, play both blind, and the second version typically reports as earlier, often by something close to the ramp that was removed.
The ear does not wait for a peak before it accepts that an event occurred. It waits for enough energy to clear the noise floor and the masking around it. A slow swell crosses that line late and gradually, so no single sample marks the start. The click supplies the start; the swell then supplies the warmth.
That layering order, transient then body then tail, is the same shape that makes revive cues in under a second work, since a revive has to read as urgent before it earns the right to be warm.
Guard the click against becoming a second event. Keep it under the body peak, keep it noise rather than a tuned ping, and stay out of the narrow band around 3 to 5 kHz where short metallic ticks live.
Engine Scheduling Stacks on Top of Whatever the Asset Does
A short attack is necessary and nowhere near sufficient. Everything between the input and the speaker adds time in series with the attack, not beside it.
- Frame rate. At 60 fps a cue triggered during the update is at least 16.7 ms behind the input; at 30 fps it is 33.3 ms. A pickup caught in a 50 Hz physics step can sit another 20 ms behind the visual.
- Mixer buffer. At 48 kHz, 256 samples is 5.3 ms, 512 samples is 10.7 ms and 1024 samples is 21.3 ms. Unity reads it through AudioSettings.GetDSPBufferSize, FMOD through setDSPBufferSize on the core system, Wwise through its initialization settings.
- Trigger path. PlayOneShot on a saturated voice pool can defer or steal. PlayScheduled against AudioSettings.dspTime hits a sample position instead of the next buffer boundary. In Wwise, PostEvent only reaches the output when RenderAudio runs.
- Platform output. Device and OS audio paths add their own latency, and Bluetooth can dominate everything above.
A five-millisecond attack on a sixty-fps build with a 512-sample buffer and a physics-triggered pickup is already about thirty-two milliseconds out before the operating system is involved. Swap in a thirty-millisecond fade and it becomes fifty-seven.
Hence the budget argument. If a heal still feels responsive up to roughly a hundred milliseconds from input to audible transient, and the chain eats forty to sixty of them, the attack has very little room to be artistic.
Cheap fixes first: preload the clip, keep one cached event instance per heal type instead of allocating one per pickup, and fire from the frame where the health value changes rather than the frame where the collider overlaps.
Measuring the Real Onset With a Screen Recording
This takes about twenty minutes and it measures the whole chain rather than the asset.
- Record at 120 fps with system audio in the same file. At 60 fps a frame is 16.7 ms; at 120 fps it is 8.3 ms.
- Flash a one-frame white rectangle on the same input event that heals, so the visual marks the trigger.
- Trigger ten heals a second apart, so nothing is decoded or paged in for the first time on the recording.
- Extract the audio at 48 kHz mono and find the first sample crossing about minus forty decibels after the flash frame.
- Repeat with the asset rendered offline. The difference between that number and the in-game number is engine plus platform.
A spectrogram beats a waveform here. The transient reads as a vertical stripe of high-frequency energy that is easy to align to a frame boundary. A stripe starting twenty milliseconds after the flash, on an asset that starts in three, is an engine number, not a sound design number.
Where the Offset Usually Comes From
Report the spread. Ten trials inside one frame mean a stable offset; ten spread over three frames mean the trigger itself is inconsistent, which usually points at voice limits, garbage collection or a first-play decode. The same method applied to constrained hardware is covered in measuring heal latency on mobile.
Fix in order: the shortest ramp that kills the click, a filtered transient in the first few milliseconds, energy above 1 kHz, engine last. If the first twenty milliseconds does not carry the message, no body design rescues the heal.