Cache PSP volume/pan computation, mix channel + master volume into mixer playback, wire boa.mp3 as looping BGM

- PSP output thread now caches the last computed leftVolume/rightVolume and
  only recomputes them when stream->volume/directionality actually changed
  since the previous chunk, instead of recomputing every ~23ms chunk
  unconditionally.
- Mixer channels and the mixer itself now carry their own volume
  (audioMixerSetChannelVolume()/audioMixerSetMasterVolume()), multiplied
  with each sound's own volume every audioMixerUpdateEarly() and applied via
  audioStreamSetVolume() - so changing a channel's or the master volume
  affects whatever's already playing, not just future sounds. Also fixed
  audioMixerUpdateEarly() to tolerate a PLAY command queued outside the
  normal per-frame cycle (no loadingAsset yet from a preceding
  audioMixerUpdateLate(), e.g. during engine startup) by leaving it queued
  for the following frame instead of asserting.
- engine.c now plays boa.mp3 on AUDIO_MIXER_CHANNEL_BGM_0 on loop through
  the mixer instead of driving a raw audiostream_t directly, exercising the
  new mixer pipeline end to end.

Built and verified on Linux, PSP (Docker) and GameCube (Docker).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-09-02 15:10:09 -05:00
co-authored by Claude Sonnet 5
parent d49594d3fb
commit d5078b978c
5 changed files with 164 additions and 44 deletions
+15
View File
@@ -141,6 +141,21 @@ typedef struct {
// pass's last, possibly-partial chunk.
bool_t readReachedEnd;
bool_t readFailed;
// Cache of the last stream->volume/directionality the output thread
// computed lastLeftVolume/lastRightVolume from - recomputing
// audioStreamGetPanFactors() and both multiplications is wasted work on
// every single chunk (~23ms) whenever neither has actually changed since
// the previous one, which is the common case outside of an active fade/
// pan. PSP itself has no persistent per-channel volume to cache this
// for us (see sceAudioOutputPannedBlocking's own call site) - hence
// caching it ourselves. Output-thread-only, like the rest of this
// section - see sceAudioOutputPannedBlocking's own call site.
float_t lastVolume;
float_t lastDirectionality;
int lastLeftVolume;
int lastRightVolume;
bool_t hasLastVolume;
} audiostreampsp_t;
/**