Files
Server_Monitor/code/audio.cpp

157 lines
3.9 KiB
C++
Raw Normal View History

2023-09-26 19:40:16 +02:00
#include "audio.h"
#include "enginestate.h"
#include <string.h>
void audio_cb(p_audio_buffer *buffer);
void audio_init()
{
audio_player *player = &engine.audio;
player->track_count = 0;
player->track_capacity = 32;
player->tracks = (audio_track *) p_alloc(player->track_capacity * sizeof(audio_track));
player->next_id = 0;
player->sample_rate = p_audio_sample_rate();
p_audio_register_data_callback(audio_cb);
}
track_id audio_add_track(p_audio_buffer *data, u32 flags)
{
// @Correctness: fix track if it has a different sample rate
audio_player *player = &engine.audio;
audio_track track;
track.id = player->next_id;
player->next_id++;
track.data = *data;
track.progress = 0;
track.playing = !(flags & AUDIO_PAUSED);
track.loop = !!(flags & AUDIO_LOOP);
track.free_on_finish = !!(flags & AUDIO_FREE_ON_FINISH);
track.volume = 1.0;
if (player->track_count + 1 < player->track_capacity)
{
u64 index = player->track_count;
player->tracks[index] = track;
player->track_count++;
}
else
{
u32 replace_index = 0;
for(u32 i = 0; i < player->track_count; i++)
{
audio_track *current = &player->tracks[i];
if(track.loop == current->loop)
{
replace_index = i;
break;
}
}
player->tracks[replace_index] = track;
}
return track.id;
}
void audio_remove_track(track_id id)
{
audio_player *player = &engine.audio;
for(int i = 0; i < player->track_count; i++)
{
audio_track *current = &player->tracks[i];
if(id == current->id)
{
u32 move_count = player->track_count - (i + 1);
if(current->free_on_finish)
p_free(current->data.samples);
memmove(current, current + 1, move_count * sizeof(audio_track));
player->track_count--;
break;
}
}
}
void audio_pause_track(track_id id)
{
audio_track *track = audio_track_from_id(id);
if(track)
track->playing = false;
}
void audio_play_track(track_id id)
{
audio_track *track = audio_track_from_id(id);
if(track)
track->playing = true;
}
void audio_change_track_volume(track_id id, f32 volume)
{
audio_track *track = audio_track_from_id(id);
if(track)
track->volume = volume;
}
audio_track *audio_track_from_id(track_id id)
{
audio_player *player = &engine.audio;
for(int i = 0; i < player->track_count; i++)
{
audio_track *current = &player->tracks[i];
if(id == current->id)
return current;
}
return NULL;
}
// @Correctness: audio cb modifies the array of tracks asynchronously. All r/w operations on tracks should be protected by a mutex.
void audio_cb(p_audio_buffer *buffer)
{
audio_player *player = &engine.audio;
buffer->size = minimum(buffer->size, 2048); // Low latency
for(u64 i = 0; i < buffer->size; i++)
{
buffer->samples[i].left = 0;
buffer->samples[i].right = 0;
}
for(int track_i = 0; track_i < player->track_count; track_i++)
{
audio_track *current = &player->tracks[track_i];
if(current->playing)
{
u64 remaining = current->data.size - current->progress;
u64 copy_count = minimum(remaining, buffer->size);
if(current->loop)
copy_count = buffer->size;
for(u64 i = 0; i < copy_count; i++)
{
buffer->samples[i].left += current->volume * current->data.samples[current->progress].left;
buffer->samples[i].right += current->volume * current->data.samples[current->progress].right;
current->progress = (current->progress + 1) % current->data.size;
}
if(!current->loop && current->progress == 0) // current->progress == 0 because we finished and then we looped around
{
// Finished playing. Remove track
u32 move_count = player->track_count - (track_i + 1);
if(current->free_on_finish)
p_free(current->data.samples); // @Bug: double free when the same sound is played 2 times. Find a way to signal we reached the end of the track so the user code can make its own free (if needed)
memmove(current, current + 1, move_count * sizeof(audio_track));
track_i--;
player->track_count--;
}
}
}
}