diff --git a/include/twn_config.h b/include/twn_config.h index 183a995..200dda2 100644 --- a/include/twn_config.h +++ b/include/twn_config.h @@ -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 diff --git a/src/twn_audio.c b/src/twn_audio.c index 5358662..08b6ce0 100644 --- a/src/twn_audio.c +++ b/src/twn_audio.c @@ -14,11 +14,9 @@ #include #include -/* 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); diff --git a/src/twn_audio_c.h b/src/twn_audio_c.h index 4ab3bde..acd2434 100644 --- a/src/twn_audio_c.h +++ b/src/twn_audio_c.h @@ -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; diff --git a/src/twn_loop.c b/src/twn_loop.c index 918edef..928b19f 100644 --- a/src/twn_loop.c +++ b/src/twn_loop.c @@ -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);