1
0
Fork 0
2022-untitled-game/code/game/engine/audio_mgr.c

168 lines
4.6 KiB
C
Raw Normal View History

2022-08-02 16:35:50 +00:00
void
audio_mgr_startup(void)
{
g_engine->audio_mgr.sound_count = NULL_HANDLE+1;
}
void
set_listener(vec3 position, vec3 front, vec3 up)
{
g_engine->audio_mgr.listener.position = position;
g_engine->audio_mgr.listener.front = front;
g_engine->audio_mgr.listener.up = up;
}
handle_t
play_sound(audio_source_t sound)
{
handle_t handle = NULL_HANDLE;
if (g_engine->audio_mgr.sound_count < MAX_AUDIO_SOURCE_COUNT)
{
// Find free handle
for (int i = NULL_HANDLE+1; i < MAX_AUDIO_SOURCE_COUNT; i++)
{
if (g_engine->audio_mgr.handle_to_index_map[i] == NULL_HANDLE)
{
handle = i;
break;
}
}
size_t new_index = g_engine->audio_mgr.sound_count;
g_engine->audio_mgr.handle_to_index_map[handle] = new_index;
g_engine->audio_mgr.index_to_handle_map[new_index] = handle;
g_engine->audio_mgr.sources[new_index] = sound;
g_engine->audio_mgr.sound_count++;
}
return handle;
}
void
stop_sound(int handle)
{
// Copy element at end into deleted element's place to maintain density
int stopped_audio_index = g_engine->audio_mgr.handle_to_index_map[handle];
size_t last_element_index = g_engine->audio_mgr.sound_count - 1;
g_engine->audio_mgr.sources[stopped_audio_index] = g_engine->audio_mgr.sources[last_element_index];
// Update maps to point to new locations
int last_element_handle = g_engine->audio_mgr.index_to_handle_map[last_element_index];
g_engine->audio_mgr.handle_to_index_map[last_element_handle] = stopped_audio_index;
g_engine->audio_mgr.index_to_handle_map[stopped_audio_index] = last_element_handle;
// Mark invalid
g_engine->audio_mgr.sources[last_element_index].type = AUDIO_TYPE_NULL;
g_engine->audio_mgr.handle_to_index_map[handle] = NULL_HANDLE;
g_engine->audio_mgr.index_to_handle_map[last_element_index] = NULL_HANDLE;
g_engine->audio_mgr.sound_count--;
}
void
update_sound_position(int handle, vec3 position)
{
(void)handle;(void)position;
int index = g_engine->audio_mgr.handle_to_index_map[handle];
transform_t* transform = get_transform(g_engine->audio_mgr.sources[index].transform);
transform->position = position;
}
void
fill_audio_buffer(uint8_t* buffer, int len)
{
// Fill with silence ahead of time
memset(buffer, 0, len);
int stop_count = 0;
int stop_handles[MAX_AUDIO_SOURCE_COUNT] = {NULL_HANDLE};
for (int i = NULL_HANDLE+1; i < g_engine->audio_mgr.sound_count; i++)
{
audio_source_t* source = &g_engine->audio_mgr.sources[i];
sound_t* sound = get_sound(source->sound);
LOG_ASSERT(sound->byte_count >= source->cursor, "Audio overflow");
int audio_bytes_remaining = sound->byte_count - source->cursor;
int bytes_to_fill = (len < audio_bytes_remaining) ? len : audio_bytes_remaining;
int samples_to_fill = bytes_to_fill / sizeof(*sound->data);
float* data = (float*)((uint8_t*)sound->data + source->cursor);
float* buf = (float*)buffer;
// Calculate angle from listener to source
float right_gain = 1.0f;
float left_gain = 1.0f;
transform_t* transform = get_transform(source->transform);
switch (source->type)
{
case AUDIO_TYPE_MUSIC:
{
right_gain = source->volume;
left_gain = source->volume;
} break;
case AUDIO_TYPE_SFX:
{
vec3 listener_right = vec3_cross(g_engine->audio_mgr.listener.front, g_engine->audio_mgr.listener.up);
vec3 listener_left = vec3_negate(listener_right);
vec3 target = vec3_sub(transform->position, g_engine->audio_mgr.listener.position);
float distance = vec3_length(target);
if (distance > 0.0f)
{
float attenuation = 1.0f / distance;
if (attenuation < 0.1f) {
attenuation = 0.0f;
} else if (attenuation > 1.0f) {
attenuation = 1.0f;
}
// TODO: Make this better. This is probably very wrong. And I don't fully understand it.
float angle_left = RAD_TO_DEG(acosf(vec3_dot(listener_left, target)/distance));
float angle_right = RAD_TO_DEG(acosf(vec3_dot(listener_right, target)/distance));
left_gain = source->volume * (angle_right/180.0f) * attenuation;
right_gain = source->volume* (angle_left/180.0f) * attenuation;
}
} break;
default: break;
}
for (int j = 0; j < samples_to_fill; j+=2)
{
// Left channel
*buf += *data * left_gain;
buf++;
data++;
// Right channel
*buf += *data * right_gain;
buf++;
data++;
}
source->cursor += bytes_to_fill;
if (source->cursor >= sound->byte_count)
{
if (source->type == AUDIO_TYPE_MUSIC) {
source->cursor = 0;
} else if (source->type == AUDIO_TYPE_SFX) {
stop_handles[stop_count++] = g_engine->audio_mgr.index_to_handle_map[i];
}
}
}
for (int i = 0; i < stop_count; i++) {
stop_sound(stop_handles[i]);
}
}