From 7fe48a5a3f65c759adf7ff4b778bcf8a18334c7b Mon Sep 17 00:00:00 2001 From: Nicholas Tay Date: Mon, 30 May 2022 21:33:19 +1000 Subject: Add a proper cache for Linux+SDL --- platform/linux.c | 64 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 14 deletions(-) (limited to 'platform') diff --git a/platform/linux.c b/platform/linux.c index 78e74aa..da8d64c 100644 --- a/platform/linux.c +++ b/platform/linux.c @@ -26,6 +26,17 @@ static bool running = true; static Display *display; static int xi_opcode; +#define AUDIO_CACHE_INITIAL 10 + +struct mixer_cache { + Mix_Chunk *chunk; + unsigned char *buffer; +}; +static struct mixer_cache *cached_chunks = NULL; +static unsigned int cached_len = 0; +/* TODO: Add a limit to the capacity? Do we panic if it's hit? */ +static unsigned int cached_capacity = AUDIO_CACHE_INITIAL; + bool sound_init(float volume) { if (SDL_Init(SDL_INIT_AUDIO) < 0) { @@ -33,34 +44,59 @@ bool sound_init(float volume) return false; } - if (Mix_OpenAudio(MIXER_FREQ, MIXER_FORMAT, MIXER_CHANNELS, MIXER_CHUNKSIZE)) { + if (Mix_OpenAudio(MIXER_FREQ, MIXER_FORMAT, MIXER_CHANNELS, MIXER_CHUNKSIZE) < 0) { printf("ERROR: SDL mixer audio device open fail.\n"); return false; } + if ((cached_chunks = malloc(AUDIO_CACHE_INITIAL * sizeof(struct mixer_cache))) == NULL) { + printf("ERROR: Could not allocate for audio cache.\n"); + return false; + } + Mix_Volume(-1, volume * MIX_MAX_VOLUME); // set for all channels return true; } -// TODO: get rid of this with proper cache thing - only supports 1 sound for now -static Mix_Chunk *loaded_chunk = NULL; +/* Find sample in cache, otherwise load into it */ +static Mix_Chunk *sound_cached(unsigned char *buffer, unsigned int buffer_len) { + /* Linear scan for now */ + for (unsigned int i = 0; i < cached_len; ++i) { + struct mixer_cache cached = cached_chunks[i]; + if (cached.buffer == buffer) + return cached.chunk; + } + + /* Not in cache; grow if required as well */ + if (cached_len >= cached_capacity) { + cached_capacity += 10; + if ((cached_chunks = realloc(cached_chunks, cached_capacity * sizeof(struct mixer_cache))) == NULL) { + printf("ERROR: Could not allocate for audio cache!\n"); + return NULL; + } + } + + SDL_RWops *sample_rw = SDL_RWFromMem(buffer, buffer_len); + Mix_Chunk *chunk = Mix_LoadWAV_RW(sample_rw, 1); + if (chunk == NULL) { + printf("ERROR: Audio sample could not be loaded - %s\n", Mix_GetError()); + return NULL; + } + + cached_chunks[cached_len++] = (struct mixer_cache){ .chunk = chunk, .buffer = buffer }; + return chunk; +} void sound_play(unsigned char *buffer, unsigned int buffer_len) { - /* Load sample into SDL memory thing then into the mixer */ - // TODO: Cache these samples as loaded into SDL - if (loaded_chunk == NULL) { - SDL_RWops *sample_rw = SDL_RWFromMem(buffer, buffer_len); - loaded_chunk = Mix_LoadWAV_RW(sample_rw, 1); - if (loaded_chunk == NULL) { - printf("ERROR: Sample load fail - %s\n", Mix_GetError()); - running = false; - return; - } + Mix_Chunk *chunk = sound_cached(buffer, buffer_len); + if (chunk == NULL) { + running = false; + return; } /* -1 means not-in-use channel */ - Mix_PlayChannel(-1, loaded_chunk, 0); + Mix_PlayChannel(-1, chunk, 0); } /* -- cgit