Add audio subsystem skeleton with a working Linux PCM playback path

Cross-platform audiostream/audio API with per-platform hooks for
PSP/Dolphin/Linux. Linux is fully wired end-to-end through SDL2
(device open, volume-mixed queueing, finish detection via
SDL_GetQueuedAudioSize) and verified playing a generated test tone
in engine.c. PSP and Dolphin hooks are stubbed for now.
This commit is contained in:
2026-08-31 10:24:02 -05:00
parent fcf0de72af
commit 8ea370a1d1
31 changed files with 1022 additions and 1 deletions
+67
View File
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "audiostreamlinux.h"
#include "audio/audiostream.h"
#include "assert/assert.h"
#include "util/memory.h"
errorret_t audioStreamLinuxInit(audiostream_t *stream) {
assertNotNull(stream, "Stream cannot be NULL.");
SDL_AudioSpec desired;
memoryZero(&desired, sizeof(SDL_AudioSpec));
desired.freq = (int) stream->pcm.sampleRate;
desired.format = AUDIO_S16SYS;
desired.channels = stream->pcm.channels;
desired.samples = 4096;
stream->platform.device = SDL_OpenAudioDevice(NULL, 0, &desired, NULL, 0);
if(stream->platform.device == 0) {
errorThrow("Failed to open SDL2 audio device: %s", SDL_GetError());
}
errorOk();
}
errorret_t audioStreamLinuxDispose(audiostream_t *stream) {
assertNotNull(stream, "Stream cannot be NULL.");
SDL_CloseAudioDevice(stream->platform.device);
errorOk();
}
errorret_t audioStreamLinuxBuffer(audiostream_t *stream) {
assertNotNull(stream, "Stream cannot be NULL.");
uint8_t *mixed = memoryAllocate(stream->dataSize);
memoryZero(mixed, stream->dataSize);
SDL_MixAudioFormat(
mixed, stream->data, AUDIO_S16SYS, (Uint32) stream->dataSize,
(stream->volume * SDL_MIX_MAXVOLUME) / 0xFF
);
int queued = SDL_QueueAudio(
stream->platform.device, mixed, (Uint32) stream->dataSize
);
memoryFree(mixed);
if(queued != 0) {
errorThrow("Failed to queue SDL2 audio data: %s", SDL_GetError());
}
SDL_PauseAudioDevice(stream->platform.device, 0);
errorOk();
}
bool_t audioStreamLinuxIsFinished(audiostream_t *stream) {
assertNotNull(stream, "Stream cannot be NULL.");
return SDL_GetQueuedAudioSize(stream->platform.device) == 0;
}