168 lines
4.6 KiB
C
168 lines
4.6 KiB
C
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]);
|
|
}
|
|
}
|
|
|