From 50c5621d8ae6edb374b993a479b8748cced23c79 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Mon, 31 Aug 2026 11:14:20 -0500 Subject: [PATCH] Fix PSP audio jitter: raise feeder thread priority above main thread Root cause of the residual jitter (correlating with framerate, per real-hardware testing): this project never overrides PSP_MAIN_THREAD_PRIORITY, so the main/render thread runs at PSPSDK's default of 32. A pthread created with default attributes (as thread_t/threadStartRequest does) runs at priority 60 - numerically higher, meaning LOWER scheduling priority on PSP's inverted scale. Under load the feeder thread was structurally guaranteed to lose scheduling contention to the main thread, starving the hardware channel's double buffer and producing audible jitter that worsens exactly when frames get slower - confirmed via disassembling PSPSDK's precompiled pthread glue (pte_osThreadGetDefaultPriority returns 60) rather than guessing. audioStreamPSPThreadFeed now self-prioritizes via sceKernelChangeThreadPriority(sceKernelGetThreadId(), 18) as the first thing it does, matching the elevated-priority pattern PSP SDK samples use for their own timing-sensitive auxiliary threads. --- src/duskpsp/audio/audiostreampsp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/duskpsp/audio/audiostreampsp.c b/src/duskpsp/audio/audiostreampsp.c index 5adc3faf..a89c872a 100644 --- a/src/duskpsp/audio/audiostreampsp.c +++ b/src/duskpsp/audio/audiostreampsp.c @@ -10,12 +10,22 @@ #include "assert/assert.h" #include "util/memory.h" #include +#include // Matches pspaudiolib's own PSP_NUM_AUDIO_SAMPLES convention - PSP audio // hardware is meant to be fed small chunks continuously, not one large // buffer per call. #define AUDIO_PSP_CHUNK_FRAMES 1024 +// PSP priorities are inverted (lower = higher priority). This project's +// main thread runs at the PSPSDK default of 32 (PSP_MAIN_THREAD_PRIORITY +// is never overridden). A pthread created with default attributes runs at +// 60 - LOWER priority than the main/render thread - so under load the +// feeder thread starves and the hardware channel underruns, heard as +// jitter/crackle that gets worse the busier (lower-fps) a frame is. Raise +// it above main so audio feeding always wins scheduling contention. +#define AUDIO_PSP_THREAD_PRIORITY 18 + errorret_t audioStreamPSPInit(audiostream_t *stream) { assertNotNull(stream, "Stream cannot be NULL."); @@ -82,6 +92,8 @@ bool_t audioStreamPSPIsFinished(audiostream_t *stream) { void audioStreamPSPThreadFeed(thread_t *thread) { assertNotNull(thread, "Thread cannot be NULL."); + sceKernelChangeThreadPriority(sceKernelGetThreadId(), AUDIO_PSP_THREAD_PRIORITY); + audiostream_t *stream = (audiostream_t *) thread->data; const size_t frameSize = stream->pcm.channels * sizeof(int16_t); const size_t totalFrames = stream->dataSize / frameSize;