diff --git a/libs/sdl2/source/audio_engine.cpp b/libs/sdl2/source/audio_engine.cpp index 6cbef475..4cd0e720 100644 --- a/libs/sdl2/source/audio_engine.cpp +++ b/libs/sdl2/source/audio_engine.cpp @@ -8,10 +8,7 @@ #include -#include -#include #include -#include #include #include @@ -39,6 +36,7 @@ namespace psemek::sdl2 audio::channel_ptr output_; + template static void callback(void * userdata, std::uint8_t * stream, int len); }; @@ -48,14 +46,23 @@ namespace psemek::sdl2 SDL_AudioSpec desired, obtained; desired.freq = audio::frequency; desired.channels = 2; - desired.format = AUDIO_S16SYS; + desired.format = AUDIO_F32SYS; desired.samples = 256; - desired.callback = &callback; + desired.callback = &callback; desired.userdata = this; if (device_ = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0); device_ == 0) - fail("SDL_OpenAudioDevice failed:"); + { + log::error() << "SDL_OpenAudioDevice failed: " << SDL_GetError(); + log::error() << "Fallback to int16 audio output"; + desired.format = AUDIO_S16SYS; + desired.callback = &callback; + if (device_ = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0); device_ == 0) + { + fail("SDL_OpenAudioDevice failed:"); + } + } - log::info() << "Initialized audio: " << static_cast(obtained.channels) << " channels, " << obtained.freq << " Hz, " << obtained.samples << " samples"; + log::info() << "Initialized audio: " << static_cast(obtained.channels) << " channels, " << obtained.freq << " Hz, " << obtained.samples << " samples " << (desired.format == AUDIO_F32SYS ? "f32" : "i16"); buffer_.resize(obtained.samples * obtained.channels); output_ = std::make_shared(); @@ -67,6 +74,7 @@ namespace psemek::sdl2 SDL_CloseAudioDevice(device_); } + template void audio_engine_impl::callback(void * userdata, std::uint8_t * dst_u8, int len) { static std::string const profiler_str = "audio"; @@ -74,7 +82,7 @@ namespace psemek::sdl2 auto self = static_cast(userdata); auto stream = self->output()->stream(); - std::int16_t * dst = reinterpret_cast(dst_u8); + SampleType * dst = reinterpret_cast(dst_u8); if (!self->thread_registered_) { @@ -82,14 +90,25 @@ namespace psemek::sdl2 self->thread_registered_ = true; } - std::size_t const size = len / 2; - std::size_t read = 0; - if (stream) - read = stream->read({self->buffer_.data(), size}); - std::fill(self->buffer_.data() + read, self->buffer_.data() + size, 0.f); + std::size_t const size = len / sizeof(SampleType); - for (auto s : self->buffer_) - *dst++ = static_cast(std::max(std::min((65535.f * s - 1.f) / 2.f, 32767.f), -32768.f)); + if constexpr (std::is_same_v) + { + std::size_t read = 0; + if (stream) + read = stream->read({self->buffer_.data(), size}); + std::fill(self->buffer_.data() + read, self->buffer_.data() + size, 0.f); + + for (auto s : self->buffer_) + *dst++ = static_cast(std::max(std::min((65535.f * s - 1.f) / 2.f, 32767.f), -32768.f)); + } + else + { + std::size_t read = 0; + if (stream) + read = stream->read({dst, size}); + std::fill(dst + read, dst + size, 0.f); + } if (auto duration = prof.duration(); duration > (size * audio::inv_frequency / 2)) log::warning() << "Audio can't keep up, callback took " << std::setprecision(5) << (1000.0 * duration) << " ms";