Repository navigation
Hot Path Audio Mono Resampling
Reviewed: November 1, 2026 · Source:
b7140848
State: Implemented in #182; no separate user toggle.
Release availability: Included in v0.8.136-0-g458730bf5373 (September 30, 2026).
Mono voices use a one-channel libsamplerate converter, then expand the resampled output into the stereo representation used downstream. Stereo voices use two channels. Both routes retain SRC_SINC_FASTEST; the held linear-resampler proposal #189 is a separate audio-quality experiment.
The older source duplicated mono input into left and right channels before feeding a persistent two-channel converter. The old “Don't do 2ch resampling” FIXME described that historical path and has been removed.
flowchart LR
A[Fetch mono source] --> B[Duplicate into L/R input]
B --> C[Two-channel sinc converter]
C --> D[Filter / HRTF / mix]
flowchart TD
A[Resolve voice channel mode] --> B{Existing converter has different channel count?}
B -->|Yes| C[Destroy incompatible converter]
B -->|No| D[Use or create converter]
C --> D
D --> E{Mono?}
E -->|Yes| F[Pack callback input into mono buffer]
F --> G[One-channel SRC_SINC_FASTEST]
G --> H[Expand resampled values into L/R]
E -->|No| I[Two-channel SRC_SINC_FASTEST]
H --> J[Existing filter / HRTF / mix]
I --> J
voice_get_samples() still supplies the voice fetch interface. voice_resample_callback() packs the left values from its two-slot source buffer into mono_resample_buf when the selected converter has one channel. voice_resample() receives mono output into a temporary buffer and calls mcpx_apu_expand_mono_samples() after interpolation. This removes the duplicate interpolation work; it does not remove all two-slot intermediate storage or downstream channel work.
The following pseudocode describes the implemented boundary, rather than an additional fallback policy:
channels = stereo ? 2 : 1
if converter exists and converter.channels != channels:
destroy converter
if converter does not exist:
create SRC_SINC_FASTEST converter for channels
read requested frames through callback
if mono:
expand each resampled value into both output channels
continue existing filtering, spatialization and mixing
The persistent converter and its recorded channel count belong to one MCPXAPUVoiceFilter. Channel-count changes destroy and recreate it. The implementation does not migrate the old converter's phase or buffered history into the new channel layout; transition behavior therefore remains a specific correctness test, rather than a promise of continuous history conversion.
VOICE_ON resets filters and destroys the previous converter so a reused voice chooses its channel layout afresh. VP reset and teardown destroy converters as well. Snapshot pre-load quiesces the APU and resets the VP; host converter pointers are not guest snapshot state. Pause/resume and active-history save/load remain useful regression cases.
Required behavior includes sample order, pitch/source progression, loops, completion/notifiers, per-channel filter histories, HRTF, multipass and monitor paths. Expansion occurs before downstream processing that can intentionally make channels differ.
#182 is the implementation and qualification history. Its older-head workload results apply to those builds and settings; they are not fresh measurements of November main. The code mechanism and stable availability are established independently of a universal game-FPS claim. Benefit depends on the share of active mono voices and resampling cost.
For future changes, compare one-channel output with each channel of the maintained two-channel reference. Exercise non-integer/changing pitch, loop boundaries, short callback reads, mono/stereo transitions, voice reuse, pause/reset, active snapshots, filters, HRTF and multipass. Record route reachability, mono/stereo frame counts, channel samples processed, worker CPU, callback p95/p99 and whole-game cadence at equal guest progress. A local interpolation reduction alone cannot establish an overall speedup.
DSP tooling guide and navigation updated November 2, 2026 for experimental PR #384, source 8f51d237. Capture/replay usage and limits.
The earlier wiki-wide review was published November 1, 2026. Emulator source: b7140848. Reviewed wiki content: 1d2b671. Current status · Release availability · Publication process.
- Home
- Current status
- Stable versus main
- Implemented mechanisms
- Controls and defaults
- Measured results and limits
- Complete change register
- System
- CPU and vCPU
- Memory and DMA
- Graphics / NV2A
- APU and audio
- Timing and timers
- Platform and I/O
- Hardware observations
- Fidelity boundaries
- Methodology
- PGR2 routes
- Debugging lag / hot paths
- Tools and commands
- DSP capture, replay and fuzzing
- HLE readiness and public XISO proof
- Concurrent DSP shadow and OpenAL proof
- DSP HLE operation inventory
- DSP HLE fix examples and testing
- Development
- Upstream shortlist
- Wiki maintenance
- Research / retired work
- Optimization catalog
- Hot-path shortcuts
- Researched experiments
- Unproven proposal directory
- PR lessons
- September26 snapshot
Repository · PRs · Issues