Fixed PSP trying to load entirely into memory

This commit is contained in:
2026-08-31 19:07:51 -05:00
parent 15bd9fc43c
commit d37109f5f7
26 changed files with 995 additions and 232 deletions
+41 -13
View File
@@ -128,7 +128,7 @@ void audioStreamPSPThreadFeed(thread_t *thread) {
}
stream->platform.playRequested = false;
const size_t totalFrames = stream->dataSize / frameSize;
const size_t totalFrames = audioStreamPcmGetTotalFrames(stream);
// loopEndFrame/loopToFrame define the loop segment [loopToFrame,
// loopEndFrame) that a looping pass wraps within, once it's reached -
@@ -147,6 +147,14 @@ void audioStreamPSPThreadFeed(thread_t *thread) {
size_t position = stream->platform.startFrame;
bool_t reachedEnd = false;
// Samples are read on demand from the asset (via audioStreamPcmRead(),
// sequentially, plus an explicit audioStreamPcmSeek() whenever jumping
// backward for a loop wrap) rather than indexed out of a fully
// resident buffer - a read/seek failure here (a corrupt or truncated
// asset, an I/O error) stops playback cleanly instead of crashing the
// thread on bad data.
bool_t readFailed = errorIsNotOk(audioStreamPcmSeek(stream, position));
// Every call always sends a full, constant-size AUDIO_PSP_CHUNK_FRAMES
// buffer - the channel is never re-declared to a different length, to
// avoid relying on sceAudioSetChannelDataLen's undocumented behavior
@@ -157,7 +165,7 @@ void audioStreamPSPThreadFeed(thread_t *thread) {
// engine's finished+looping path is designed for platforms with no
// better option (see audiostream.c), but here the thread can just
// keep going and call onLoop itself instead.
while(!threadShouldStop(thread) && !reachedEnd) {
while(!readFailed && !threadShouldStop(thread) && !reachedEnd) {
// Normally bounded by loopEndFrame (the loop segment's end), but a
// seek can legitimately land past it (e.g. into an outro after the
// loop point) - in that case play out to the true end of the buffer
@@ -173,9 +181,22 @@ void audioStreamPSPThreadFeed(thread_t *thread) {
const bool_t willLoop = reachesEndThisChunk &&
(stream->state & AUDIO_STREAM_STATE_LOOPING);
memoryCopy(
chunk, stream->data + (position * frameSize), framesThisChunk * frameSize
);
size_t framesRead = 0;
if(errorIsNotOk(
audioStreamPcmRead(stream, chunk, framesThisChunk, &framesRead)
)) {
readFailed = true;
break;
}
if(framesRead < framesThisChunk) {
// The asset is shorter than its declared header size (corrupt or
// truncated) - pad what's missing with silence rather than play
// whatever was left in `chunk` from a previous pass.
memoryZero(
chunk + (framesRead * channels),
(framesThisChunk - framesRead) * frameSize
);
}
const size_t remainderFrames = AUDIO_PSP_CHUNK_FRAMES - framesThisChunk;
size_t wrapFrames = 0;
@@ -205,15 +226,22 @@ void audioStreamPSPThreadFeed(thread_t *thread) {
wrapFrames = remainderFrames < loopSegmentFrames
? remainderFrames
: loopSegmentFrames;
memoryCopy(
chunk + (framesThisChunk * channels),
stream->data + (loopToFrame * frameSize),
wrapFrames * frameSize
);
if(wrapFrames < remainderFrames) {
if(errorIsNotOk(audioStreamPcmSeek(stream, loopToFrame))) {
readFailed = true;
break;
}
size_t wrapRead = 0;
if(errorIsNotOk(audioStreamPcmRead(
stream, chunk + (framesThisChunk * channels), wrapFrames, &wrapRead
))) {
readFailed = true;
break;
}
if(wrapRead < remainderFrames) {
memoryZero(
chunk + ((framesThisChunk + wrapFrames) * channels),
(remainderFrames - wrapFrames) * frameSize
chunk + ((framesThisChunk + wrapRead) * channels),
(remainderFrames - wrapRead) * frameSize
);
}
} else if(reachesEndThisChunk) {