#include "simple_audio.h" #define MA_NO_DECODING #define MA_NO_ENCODING #define MA_NO_RESOURCE_MANAGER #define MA_NO_NODE_GRAPH #define MA_NO_ENGINE #define MINIAUDIO_IMPLEMENTATION #include #include #include #include #include #define RATE 48000 #define SLOTS 32 static ma_device device; static ma_mutex mutex; static int opened, active; static uint32_t cursor; static struct { int16_t *pcm; uint32_t count; } sounds[SLOTS]; // Only native-owned immutable PCM is read on the audio thread. The lock covers // a bounded copy, never allocation, synthesis, device calls, or Simple code. static void output(ma_device *unused, void *out, const void *in, ma_uint32 frames) { (void)unused; (void)in; memset(out,0,frames*sizeof(int16_t)); ma_mutex_lock(&mutex); if (active) { uint32_t count=sounds[active].count-cursor; if (count>frames) count=frames; memcpy(out,sounds[active].pcm+cursor,count*sizeof(int16_t)); cursor+=count; if (cursor==sounds[active].count) active=0; } ma_mutex_unlock(&mutex); } static int32_t load(const int16_t *pcm, uint32_t count) { if (!opened || !pcm || !count || count>RATE*10) return -1; int slot; for (slot=4; slot=SLOTS || !sounds[sound].pcm) return -1; ma_mutex_lock(&mutex); active=sound; cursor=0; ma_mutex_unlock(&mutex); return 0; } static int32_t stop(void) { if (opened) { ma_mutex_lock(&mutex); active=0; ma_mutex_unlock(&mutex); } return 0; } static int32_t playing(void) { if (!opened) return 0; ma_mutex_lock(&mutex); int result=active!=0; ma_mutex_unlock(&mutex); return result; } static void close_audio(void) { if (!opened) return; ma_device_uninit(&device); // Joins callback before freeing buffers/mutex. ma_mutex_uninit(&mutex); for (int i=1;i