Skip to content
PS5PCEM
PartialAudio and video

ACM convolution

ACM convolution runs FMOD's partitioned reverb on the CPU. Shared-input batches transform one dry signal, apply float or half-float impulse partitions, and overlap-add the wet result.

Repository notes through October 10, 2026

The bug it closed

Subnautica: Below Zero could start with a crackle, fall silent, and recover minutes later. The PCM reaching the host device contained non-finite floats. An in-memory trace of FMOD's DSP callbacks showed finite audio entering the convolution reverb and garbage leaving it. The HLE functions sceAcm_ConvReverb_SharedInput, the batch submit and sceAcmBatchWait were returning success without writing an output.

FMOD then mixed that unwritten wet buffer into the graph. The NaNs spread through later effects. AudioOut's sanitizer replaced them with silence and could not repair the poisoned filter history. A second error made the wait on the initial batch identifier -1 succeed. FMOD treats a failed initial wait as 'there is no previous wet buffer yet' and only mixes after a real completed job.

Partitioned convolution

The descriptor layout matches the one observed in FMOD's ACM backend. Impulse-response partitions are interleaved complex bins. A block of B bins belongs to a transform of length 2B. Input, output and overlap buffers are separate and planar. Only the observed zero-offset float32 and float16 spectrum layouts are accepted.

A batch runs on the CPU. Input history is kept across grains and across the ring wrap, and the overlap is carried into the next output grain. Several outputs can share one input transform and one history advance. Mono input can feed more than one channel. The inverse transform is normalized. An independent inverse of a real impulse partition put its energy in the first half of the zero-padded block, which confirms the spectrum sign. The packed impulse the game uses omits the Nyquist bin.

Waits, limits and the retest

Builders capture pointer arrays and gains into a bounded command record. The PCM itself is read when the batch starts. A wait succeeds only for a batch that this context actually completed. Destroying the context releases the history. Invalid bounds, unknown command encodings and unsupported layouts return errors.

Standalone ACM FFT, IFFT and panner operations are not implemented. Channels are capped at 8, outputs at 32 and the block at 1024. History storage is bounded. On the signed runner, 90 once-per-second PCM snapshots contained no non-finite samples, with a peak of 0.1255 and the first audio above 0.001 at 11.03 seconds. The maintainer confirmed the sound. The samples are a probe, not every sample the game emitted.

What is implemented

  • Partitioned FFT convolution for FMOD's shared-input and shared-IR reverb batches.
  • Float32 and float16 complex spectra, overlap-add, and history across grains.
  • Waits that succeed only for a completed batch of that context. The initial -1 identifier fails.
  • Finite PCM on the Subnautica retest, with the crackle and the later silence gone.

What is still missing

  • Standalone ACM FFT, IFFT and panner calls are unimplemented.
  • Nonzero spectrum offsets and unmeasured routing layouts are rejected.
  • The convolution runs on the CPU. There is no GPU FFT path.

Related mechanisms

What these pages are

The text follows the architecture notes and the October 2026 reports in the PS5PCEM repository. A focused test passing is not a new frame rate and not a new playthrough.

All technologies