Skip to content

feature(audio): resample N64 audio to native 48 kHz output#1106

Closed
bassdr wants to merge 1 commit into
Kenix3:mainfrom
bassdr:feature/AudioResampler
Closed

feature(audio): resample N64 audio to native 48 kHz output#1106
bassdr wants to merge 1 commit into
Kenix3:mainfrom
bassdr:feature/AudioResampler

Conversation

@bassdr

@bassdr bassdr commented May 19, 2026

Copy link
Copy Markdown

Shipwright audio engine produces PCM at 32 kHz — the console's native sample rate. Most modern audio devices run at 48 kHz. Without explicit resampling, the OS or driver performs an implicit conversion of unknown quality, often introducing aliasing artifacts.
This PR adds a clean resampling step inside AudioPlayer::Play(), between the game's audio engine and the backend (SDL, PipeWire, WASAPI, CoreAudio). The resampler is transparent to all backends — they simply open the device at 48 kHz as they would normally.
The 32 kHz → 48 kHz ratio is exactly 3/2, which allows a compact polyphase filter (8 taps per phase) with good stopband rejection (~60 dB). The output buffer is stack-allocated to avoid any heap allocation on the audio hot path.

  • AudioSettings gains SourceSampleRate (default 0 = passthrough)
  • AudioPlayer::Play() resamples transparently before DoPlay() when SourceSampleRate != SampleRate
  • GetDesiredBuffered() scales from source rate to output rate so OTRAudio_Thread fill logic remains coherent
  • Resample output uses a fixed std::array<int16_t, 16384> — no heap allocation on the audio hot path
  • Default SampleRate changed from 44100 to 48000 Hz
  • AudioPlayer destructor made virtual to fix UB in derived class dtors

@bassdr bassdr changed the title audio: add polyphase sinc resampler and SourceSampleRate support feature(audio): add polyphase sinc resampler and SourceSampleRate support May 19, 2026
@bassdr bassdr changed the title feature(audio): add polyphase sinc resampler and SourceSampleRate support feature(audio): resample N64 audio to native 48 kHz output May 20, 2026
@bassdr bassdr force-pushed the feature/AudioResampler branch from 42bdd6a to 7f74473 Compare May 30, 2026 17:28
@bassdr bassdr force-pushed the feature/AudioResampler branch 2 times, most recently from 39b0efd to d3da2f8 Compare June 1, 2026 22:52
@bassdr bassdr force-pushed the feature/AudioResampler branch from d3da2f8 to c5c6ecf Compare June 12, 2026 15:13
Add AudioResampler, a polyphase windowed-sinc resampler supporting
arbitrary integer ratios. Designed for N64 audio upsampling from
32000 Hz to 48000 Hz (exact ratio 3/2, P=3 Q=2, 8 taps/phase,
Kaiser window beta=6, ~60 dB stopband attenuation).

- AudioSettings gains SourceSampleRate (default 0 = passthrough)
- AudioPlayer::Play() resamples transparently before DoPlay() when
  SourceSampleRate != SampleRate
- GetDesiredBuffered() scales from source rate to output rate so
  OTRAudio_Thread fill logic remains coherent
- Resample output uses a fixed std::array<int16_t, 16384> — no heap
  allocation on the audio hot path
- Default SampleRate changed from 44100 to 48000 Hz
- AudioPlayer destructor made virtual to fix UB in derived class dtors
@bassdr bassdr force-pushed the feature/AudioResampler branch from c5c6ecf to a7cdd52 Compare June 18, 2026 00:46
@bassdr

bassdr commented Jun 23, 2026

Copy link
Copy Markdown
Author

Changes moved in HarbourMasters/Shipwright#6668, now self-contained, not needed in LUS anymore.

@bassdr bassdr closed this Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant