Enforce strict limit of 64 active sources;

If 64 sources are playing and a new one is started, Source:play will
return false.

Instead of a linked list, a static list of 64 Sources is used.

Bit scanning intrinsics are used to efficiently iterate the list,
using a mask (still deciding on this).
This commit is contained in:
bjorn 2021-02-16 21:14:40 -07:00 committed by Bjorn
parent 4580107023
commit 75fda2336f
3 changed files with 25 additions and 13 deletions

View File

@ -14,11 +14,13 @@
#define LOVR_THREAD_LOCAL __declspec(thread)
#define LOVR_ALIGN(n) __declspec(align(n))
#define LOVR_RESTRICT __restrict
#define LOVR_CTZLL _tzcnt_u64
#else
#define LOVR_NORETURN __attribute__((noreturn))
#define LOVR_THREAD_LOCAL __thread
#define LOVR_ALIGN(n) __attribute__((aligned(n)))
#define LOVR_RESTRICT restrict
#define LOVR_CTZLL __builtin_ctzll
#endif
#ifndef M_PI

View File

@ -15,12 +15,11 @@ static const ma_format miniaudioFormats[] = {
#define OUTPUT_FORMAT SAMPLE_F32
#define OUTPUT_CHANNELS 2
#define CAPTURE_CHANNELS 1
#define MAX_SOURCES 64
#define BUFFER_SIZE 256
struct Source {
uint32_t ref;
Source* next;
uint32_t index;
Sound* sound;
ma_data_converter* converter;
intptr_t spatializerMemo;
@ -28,7 +27,6 @@ struct Source {
float volume;
float position[4];
float orientation[4];
bool tracked;
bool playing;
bool looping;
bool spatial;
@ -39,7 +37,8 @@ static struct {
ma_context context;
ma_device devices[2];
ma_mutex lock;
Source* sources;
Source* sources[MAX_SOURCES];
uint64_t sourceMask;
Sound* captureStream;
arr_t(ma_data_converter*) converters;
float position[4];
@ -82,10 +81,15 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
memset(dst, 0, sizeof(state.leftovers));
}
for (Source** list = &state.sources, *source = *list; source != NULL; source = *list) {
// Biterate the source mask to iterate over all active Sources
for (uint64_t mask = state.sourceMask, lobit = mask & -mask; mask != 0; mask ^= lobit, lobit = mask & -mask) {
uint32_t index = LOVR_CTZLL(mask);
Source* source = state.sources[index];
if (!source->playing) {
*list = source->next;
source->tracked = false;
source->index = ~0u;
state.sources[index] = NULL;
state.sourceMask &= ~(1ull << index);
lovrRelease(source, lovrSourceDestroy);
continue;
}
@ -135,8 +139,6 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
for (uint32_t i = 0; i < OUTPUT_CHANNELS * BUFFER_SIZE; i++) {
dst[i] += src[i] * volume;
}
list = &source->next;
}
// Tail
@ -326,6 +328,7 @@ Source* lovrSourceCreate(Sound* sound, bool spatial) {
Source* source = calloc(1, sizeof(Source));
lovrAssert(source, "Out of memory");
source->ref = 1;
source->index = ~0u;
source->sound = sound;
lovrRetain(source->sound);
@ -386,15 +389,21 @@ void lovrSourceDestroy(void* ref) {
}
bool lovrSourcePlay(Source* source) {
if (state.sourceMask == ~0ull) {
return false;
}
ma_mutex_lock(&state.lock);
source->playing = true;
if (!source->tracked) {
// If the source isn't tracked, set its index to the right-most zero bit in the mask
if (source->index == ~0u) {
uint32_t index = state.sourceMask ? LOVR_CTZLL(~state.sourceMask) : 0;
state.sourceMask |= (1ull << index);
state.sources[index] = source;
source->index = index;
lovrRetain(source);
source->tracked = true;
source->next = state.sources;
state.sources = source;
}
ma_mutex_unlock(&state.lock);

View File

@ -5,6 +5,7 @@
#pragma once
#define PLAYBACK_SAMPLE_RATE 48000
#define MAX_SOURCES 64
struct Sound;