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 KEYBIND_SLOTS_DEFAULT 3
#define AUDIO_FREQUENCY 48000 #define AUDIO_FREQUENCY 48000
#define AUDIO_N_CHANNELS 2
#define TEXT_FONT_TEXTURE_SIZE_DEFAULT 2048 #define TEXT_FONT_TEXTURE_SIZE_DEFAULT 2048
#define TEXT_FONT_OVERSAMPLING_DEFAULT 4 #define TEXT_FONT_OVERSAMPLING_DEFAULT 4

View File

@ -14,11 +14,9 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
/* TODO: default to float sampling format? */ static const char *audio_exts[AUDIO_FILE_TYPE_COUNT] = {
".ogg", /* AUDIO_FILE_TYPE_OGG */
static const char *audio_exts[audio_file_type_count] = { ".xm", /* AUDIO_FILE_TYPE_XM */
".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) { static AudioFileType infer_audio_file_type(const char *path) {
size_t path_len = SDL_strlen(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]); size_t ext_length = SDL_strlen(audio_exts[i]);
if (path_len <= ext_length) if (path_len <= ext_length)
continue; continue;
@ -77,7 +75,7 @@ static AudioFileType infer_audio_file_type(const char *path) {
return (AudioFileType)i; 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? */ /* or should we expect things to simply fail? */
static union AudioContext init_audio_context(const char *path, AudioFileType type) { static union AudioContext init_audio_context(const char *path, AudioFileType type) {
switch (type) { switch (type) {
case audio_file_type_ogg: { case AUDIO_FILE_TYPE_OGG: {
unsigned char *data; unsigned char *data;
int64_t len = get_audio_data(path, &data); int64_t len = get_audio_data(path, &data);
if (len == -1) { 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; unsigned char *data;
int64_t len = get_audio_data(path, &data); int64_t len = get_audio_data(path, &data);
if (len == -1) { if (len == -1) {
@ -148,12 +146,12 @@ static union AudioContext init_audio_context(const char *path, AudioFileType typ
static void repeat_audio(AudioChannel *channel) { static void repeat_audio(AudioChannel *channel) {
switch (channel->file_type) { switch (channel->file_type) {
case audio_file_type_ogg: { case AUDIO_FILE_TYPE_OGG: {
stb_vorbis_seek_start(channel->context.vorbis.handle); stb_vorbis_seek_start(channel->context.vorbis.handle);
break; break;
} }
case audio_file_type_xm: { case AUDIO_FILE_TYPE_XM: {
xm_restart(channel->context.xm.handle); xm_restart(channel->context.xm.handle);
break; 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, static void audio_mixin_streams(const AudioChannel *channel,
uint8_t *restrict a, uint8_t *restrict a,
uint8_t *restrict b, uint8_t *restrict b,
size_t frames) size_t frames)
{ {
int16_t *const sa = (int16_t *)a; float *const sa = (float *)a;
int16_t *const sb = (int16_t *)b; float *const sb = (float *)b;
const float left_panning = fminf(fabsf(channel->args.panning - 1.0f), 1.0f); 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); 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) { for (size_t s = 0; s < frames; s += 2) {
/* left channel */ /* 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 */ /* 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) int len)
{ {
static uint8_t buffer[16384]; 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 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) { switch (channel->file_type) {
case audio_file_type_ogg: { case AUDIO_FILE_TYPE_OGG: {
/* feed stream for needed conversions */ /* feed stream for needed conversions */
for (int i = 0; i < stream_frames; ) { for (int i = 0; i < stream_frames; ) {
const int n_frames = (stream_frames - i) > int16_buffer_frames ? const int n_frames = (stream_frames - i) > float_buffer_frames ?
int16_buffer_frames : stream_frames - i; 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.handle,
channel->context.vorbis.channel_count, channel->context.vorbis.channel_count,
(int16_t *)buffer, (float *)buffer,
n_frames); n_frames);
/* handle end of file */ /* handle end of file */
@ -272,7 +264,7 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
/* panning and mixing */ /* panning and mixing */
audio_mixin_streams(channel, audio_mixin_streams(channel,
&stream[i * sizeof(int16_t)], buffer, &stream[i * sizeof(float)], buffer,
samples_per_channel * 2); samples_per_channel * 2);
i += samples_per_channel * 2; i += samples_per_channel * 2;
@ -281,7 +273,7 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
break; break;
} }
case audio_file_type_xm: { case AUDIO_FILE_TYPE_XM: {
for (int i = 0; i < stream_frames; ) { for (int i = 0; i < stream_frames; ) {
const int n_frames = (stream_frames - i) > float_buffer_frames ? const int n_frames = (stream_frames - i) > float_buffer_frames ?
float_buffer_frames : stream_frames - i; float_buffer_frames : stream_frames - i;
@ -301,13 +293,9 @@ static void audio_sample_and_mixin_channel(const AudioChannel *channel,
break; 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 */ /* panning and mixing */
audio_mixin_streams(channel, audio_mixin_streams(channel,
&stream[i * sizeof(int16_t)], &stream[i * sizeof(float)],
buffer, buffer,
samples_per_channel * 2); samples_per_channel * 2);

View File

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

View File

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