twn_audio: settle down on float32 2-channel sampling only, format enums to style used elsewhere

This commit is contained in:
veclav talica 2024-10-01 12:59:01 +03:00
parent 57fe5e8946
commit a0ea657eb9
4 changed files with 31 additions and 42 deletions

View File

@ -16,7 +16,6 @@
#define KEYBIND_SLOTS_DEFAULT 3
#define AUDIO_FREQUENCY 48000
#define AUDIO_N_CHANNELS 2
#define TEXT_FONT_TEXTURE_SIZE_DEFAULT 2048
#define TEXT_FONT_OVERSAMPLING_DEFAULT 4

View File

@ -14,11 +14,9 @@
#include <stdint.h>
#include <string.h>
/* TODO: default to float sampling format? */
static const char *audio_exts[audio_file_type_count] = {
".ogg", /* audio_file_type_ogg */
".xm", /* audio_file_type_xm */
static const char *audio_exts[AUDIO_FILE_TYPE_COUNT] = {
".ogg", /* AUDIO_FILE_TYPE_OGG */
".xm", /* AUDIO_FILE_TYPE_XM */
};
@ -68,7 +66,7 @@ void audio_play(const char *path, const char *channel) {
static AudioFileType infer_audio_file_type(const char *path) {
size_t path_len = SDL_strlen(path);
for (int i = 0; i < audio_file_type_count; ++i) {
for (int i = 0; i < AUDIO_FILE_TYPE_COUNT; ++i) {
size_t ext_length = SDL_strlen(audio_exts[i]);
if (path_len <= ext_length)
continue;
@ -77,7 +75,7 @@ static AudioFileType infer_audio_file_type(const char *path) {
return (AudioFileType)i;
}
return audio_file_type_unknown;
return AUDIO_FILE_TYPE_UNKNOWN;
}
@ -85,7 +83,7 @@ static AudioFileType infer_audio_file_type(const char *path) {
/* or should we expect things to simply fail? */
static union AudioContext init_audio_context(const char *path, AudioFileType type) {
switch (type) {
case audio_file_type_ogg: {
case AUDIO_FILE_TYPE_OGG: {
unsigned char *data;
int64_t len = get_audio_data(path, &data);
if (len == -1) {
@ -112,7 +110,7 @@ static union AudioContext init_audio_context(const char *path, AudioFileType typ
};
}
case audio_file_type_xm: {
case AUDIO_FILE_TYPE_XM: {
unsigned char *data;
int64_t len = get_audio_data(path, &data);
if (len == -1) {
@ -148,12 +146,12 @@ static union AudioContext init_audio_context(const char *path, AudioFileType typ
static void repeat_audio(AudioChannel *channel) {
switch (channel->file_type) {
case audio_file_type_ogg: {
case AUDIO_FILE_TYPE_OGG: {
stb_vorbis_seek_start(channel->context.vorbis.handle);
break;
}
case audio_file_type_xm: {
case AUDIO_FILE_TYPE_XM: {
xm_restart(channel->context.xm.handle);
break;
}
@ -209,30 +207,25 @@ PlayAudioArgs audio_get_default_args(void) {
}
/* this assumes int16_t based streams */
/* this assumes float based streams */
static void audio_mixin_streams(const AudioChannel *channel,
uint8_t *restrict a,
uint8_t *restrict b,
size_t frames)
{
int16_t *const sa = (int16_t *)a;
int16_t *const sb = (int16_t *)b;
float *const sa = (float *)a;
float *const sb = (float *)b;
const float left_panning = fminf(fabsf(channel->args.panning - 1.0f), 1.0f);
const float right_panning = fminf(fabsf(channel->args.panning + 1.0f), 1.0f);
#if AUDIO_N_CHANNELS == 2
for (size_t s = 0; s < frames; s += 2) {
/* left channel */
sa[s] += (int16_t)(sb[s] * channel->args.volume * left_panning);
sa[s] += (float)(sb[s] * channel->args.volume * left_panning);
/* right channel */
sa[s + 1] += (int16_t)(sb[s + 1] * channel->args.volume * right_panning);
sa[s + 1] += (float)(sb[s + 1] * channel->args.volume * right_panning);
}
#else
#error "Unimplemented channel count"
#endif
}
@ -242,21 +235,20 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
int len)
{
static uint8_t buffer[16384];
const int int16_buffer_frames = sizeof (buffer) / sizeof (int16_t);
const int float_buffer_frames = sizeof (buffer) / sizeof (float);
const int stream_frames = len / (int)(sizeof (int16_t));
const int stream_frames = len / (int)(sizeof (float));
switch (channel->file_type) {
case audio_file_type_ogg: {
case AUDIO_FILE_TYPE_OGG: {
/* feed stream for needed conversions */
for (int i = 0; i < stream_frames; ) {
const int n_frames = (stream_frames - i) > int16_buffer_frames ?
int16_buffer_frames : stream_frames - i;
const int n_frames = (stream_frames - i) > float_buffer_frames ?
float_buffer_frames : stream_frames - i;
const int samples_per_channel = stb_vorbis_get_samples_short_interleaved(
const int samples_per_channel = stb_vorbis_get_samples_float_interleaved(
channel->context.vorbis.handle,
channel->context.vorbis.channel_count,
(int16_t *)buffer,
(float *)buffer,
n_frames);
/* handle end of file */
@ -272,7 +264,7 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
/* panning and mixing */
audio_mixin_streams(channel,
&stream[i * sizeof(int16_t)], buffer,
&stream[i * sizeof(float)], buffer,
samples_per_channel * 2);
i += samples_per_channel * 2;
@ -281,7 +273,7 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
break;
}
case audio_file_type_xm: {
case AUDIO_FILE_TYPE_XM: {
for (int i = 0; i < stream_frames; ) {
const int n_frames = (stream_frames - i) > float_buffer_frames ?
float_buffer_frames : stream_frames - i;
@ -301,13 +293,9 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
break;
}
/* convert floats to int16_t */
for (int p = 0; p < samples_per_channel * 2; ++p)
((int16_t *)buffer)[p] = (int16_t)(((float *)buffer)[p] * (float)INT16_MAX);
/* panning and mixing */
audio_mixin_streams(channel,
&stream[i * sizeof(int16_t)],
&stream[i * sizeof(float)],
buffer,
samples_per_channel * 2);

View File

@ -14,10 +14,10 @@
typedef enum AudioFileType {
audio_file_type_ogg,
audio_file_type_xm,
audio_file_type_count,
audio_file_type_unknown,
AUDIO_FILE_TYPE_OGG,
AUDIO_FILE_TYPE_XM,
AUDIO_FILE_TYPE_COUNT,
AUDIO_FILE_TYPE_UNKNOWN,
} AudioFileType;

View File

@ -383,14 +383,16 @@ static bool initialize(void) {
SDL_zero(request);
request.freq = AUDIO_FREQUENCY;
request.format = AUDIO_S16;
request.channels = AUDIO_N_CHANNELS;
request.format = AUDIO_F32;
request.channels = 2;
request.callback = audio_callback;
/* TODO: check for errors */
ctx.audio_device = SDL_OpenAudioDevice(NULL, 0, &request, &got, 0);
ctx.audio_stream_format = got.format;
ctx.audio_stream_frequency = got.freq;
ctx.audio_stream_channel_count = got.channels;
SDL_assert_always(got.format == AUDIO_F32);
SDL_assert_always(got.channels == 2);
SDL_PauseAudioDevice(ctx.audio_device, 0);