System info & network
This commit is contained in:
156
code/audio.cpp
Normal file
156
code/audio.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user